/*
2009.7.31 support zkfp 10.0 by Zhang Honggen
*/
#ifdef _FORTIFY_SOURCE
#undef _FORTIFY_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cmds.h"
#include "bmp.h"
#include "zkemsdk.h"
#include "commpro.h"
#include "zkfinger.h"
#include "ZFTemplate.h"
#include "utils.h"
//henry add att count at this,only for A9
#include "att.h"
#include "commapi.h"

#define PIN2SUPPORT

#ifdef WIN32
#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "commpro___x64_Debug/commpro.lib")
#else
#pragma comment(lib, "commpro___WIN32_Debug/commpro.lib")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "commpro___x64_Release/commpro.lib")
#else
#pragma comment(lib, "commpro___WIN32_Release/commpro.lib")
#endif
#endif
#endif

#define VER504 "Ver 5.04"	//????Pin2???z
#define VER511 "Ver 5.11"	//???????????
#define VER601 "Ver 6.01"	//????????????????
#define VER660	"Ver 6.60"
#define VER61820070807 "Ver 6.18 20070807" //????��????��?????????
#define HTZID 103	//?????ID?

#define ZKFPV10					10
#define ZKFPV10_FINGER_INDEX	15
//4?????????
#define AttLogSize1 4
//8????????????
#define AttLogSize2 8
static const char * monname[12]={
	"Jan","Feb","Mar","Apr",
	"May","Jun","Jul","Aug",
	"Sep","Oct","Nov","Dec"
};
//dsl 2007.7.30
#define RTLOGSIZE 14 //14->16???????��
//dsl 2007.9.20
#define NEWRTLOGSIZE 16
//dsl 2007.10.9
#define TFTRTLOGSIZE 36

//???????10????????
#define CGP_MAX 10
//?????????????
#define CGP_MEMBER_MAX 5
//??????��??
#define MAXTZNO 50
//??��???��??
#define MINTZNO 1
//?????????
#define MINHOLIDAYNO 24

#define HTZ_START 0
#define	HTZ_END 1
#define HTZ_MONTH 0
#define HTZ_DAY 1

#define MAXVALIDTMPSIZE 598 //for 4 bytes aligned

//2014-11-26 scar parameter
#define PARAMETERCODE_COMPATOLDFIRMWARE	0x1


static int SSR_GetPIN1(UDK_HANDLE Handle, char * PIN2);

//15????????
/*
enum __VERIFY_STYLE
{
VS_FP_OR_PW_OR_RF=0,	//1
VS_FP,
VS_PIN,
VS_PW,
VS_RF,					//5
VS_FP_OR_PW,
VS_FP_OR_RF,
VS_PW_OR_RF,
VS_PIN_AND_FP,
VS_FP_AND_PW,			//10
VS_FP_AND_RF,
VS_PW_AND_RF,
VS_FP_AND_PW_AND_RF,
VS_PIN_AND_FP_AND_PW,
VS_FP_AND_RF_OR_PIN,	//15
VS_NUM=15
};*/

void ConvertMonth(char *version)
{
	int i;
	for(i=0;i<12;i++)
		if(strncmp(version+9, monname[i], 3)==0)
			break;
	i++;
	version[9]=version[16];
	version[10]=version[17];
	version[11]=version[18];
	version[12]=version[19];
	version[15]=version[13];
	version[16]=version[14];
	if(i<10)
	{
		version[13]='0';
		version[14]='0'+i;
	}
	else
	{
		version[13]='1';
		version[14]='0'+i-10;
	}
	version[17]=0;
}

typedef struct _FPindex_{
	int index0;
	int index1;
	int index2;
	int index3;
	int index4;
	int index5;
	int index6;
	int index7;
	int index8;
	int index9;
}TFPindex, *PFPindex;

typedef struct _emh_{
	UDK_HANDLE emh;
	char *Buffer;
	int BufferLen;
	int UserSize, TmpSize,ALogSize, OLogSize, UserBufferLen, UDataSize, OLogSizeEx;
	char *UserBuffer, *TmpBuffer, *ALogBuffer, *OLogBuffer, *UDataBuffer, *OLogBufferEx;
	char *cUserBuffer, *cTmpBuffer, *cALogBuffer, *cOLogBuffer, *cUDataBuffer, *cOLogBufferEx;
	//henry add for SSR ,about begin SSR 06-09 
	char *cAttRuleBuffer,*aAttRuleBuffer,*cDPTBuffer,*aDPTBuffer,*cTurnBuffer,*aTurnBuffer;
	int AttRulueLen,DPTBufferLen,TrunBufferLen;
	int WaitTimeForACommand;
	int WaitTimeFor1KData;
	int LastCmd;
	UDK_U32 LastTime;
	int PINWidth;
	char version[50];
	int DeviceType;	//0:Zem100;1:Zem200
	int IsBatchUpdate;
	int IsForceUpdate;
	char *TmpOpBuf, *UserInfoOpBuf, *TmpsBuf;
	int  TmpOpBufLen,UserInfoOpBufLen,TmpsBufLen;
	char *BatchTmpUserInfo;
	int BatchTmpSize;
	int ExtendFmt;
	int dcTmp, dcUser, dcLog, dcInit; 
	int BlockSize;
	int RTLogNum;
	int NewSmsFormat;//dsl.2007.07.04.??????SMS	
	int Dialup; // dsl. 207.7.5.???GPRS??????????MODEM?????????
	char Telephone[20];
	int IsNewRTStru;//dsl 2007.9.20
	int IsTFTMachine; //dsl 2007.10.8;
	int InnerID; //dsl 2007.10.31.????????????????????????????????????????????????Z_SetUserInfoEx?????
	char *UserIDs; //UserIDs[0x10000] to *UserIDs dsl 2008.7.25????��???????.
	int LastCount;//dsl
	char *GetRTLogStartAddr; //dsl 2008.7.24
	char *GetRTLogLoopAddr; //dsl 2008.7.24
	char *ReadRTLogBuf;
	int RTLogSize;
	int ExtendOPLog; //yuping, 9��???????bug????
	TEmKeyOptions EmKeyOptions;
	TFPindex fingerquicksearch[50003];
	int isfingerquick;//???????????????
	int lastpin;
	int libusb_flag;
	int wififlag;
	UDK_BOOL bNewFirmware;
}TEmHandle, *PEmHandle;

typedef struct _AttLog_{
	int PIN;
	char verified;
	UDK_S32 time_second;
	char status;
}TAttLog, *PAttLog;

char* pAttLogs1,pAttLogs2;

#pragma pack(push)
#pragma pack(1)
typedef struct _UserOld_{
	UDK_U16 PIN;
	UDK_U8 Privillege;
	char Password[5];
	char Name[8];
}TUserOld, *PUserOld;

//?���?????????
typedef struct _User_{
	UDK_U16 PIN;
	UDK_U8 Privillege;
	char Password[5];
	char Name[8];
	UDK_U8 Card[5];		//??????????��?????ID???????
	UDK_U8 Group;		//????????????
	UDK_U16 TimeZones;	//???????????��?��???
	UDK_U32 PIN2;		//32��?????????????
}TUser, *PUser;	//26 byte

typedef struct _SMS_{
	UDK_U8 Tag;		//???
	UDK_U16 ID; 		//????????? 0???????????��
	UDK_U16 ValidMinutes; 	//??��??????   ????????
	UDK_U16 Reserved;
	UDK_U32 StartTime; 		//??????
	UDK_U8 Content[MAX_SMS_CONTENT_SIZE+1];   //?????????
}TSms, *PSms;    //60 Bytes

//dsl.2007.07.04.??????SMS
typedef struct _SMSNEW_{
	UDK_U8 Tag;		//???
	UDK_U16 ID; 		//????????? 0???????????��
	UDK_U16 ValidMinutes; 	//??��??????   ????????
	UDK_U16 Reserved;
	UDK_U32 StartTime; 		//??????
	UDK_U8 Content[MAX_SMSNEW_CONTENT_SIZE+1];   //?????????
}TSmsNew, *PSmsNew;    //60 Bytes

typedef struct _RTLog_{
	UDK_U16 EventType;
	char Data[RTLOGSIZE];//14
}TRTLog, *PRTLog;

typedef struct _NewRTLog_{
	UDK_U16 EventType;
	char Data[NEWRTLOGSIZE];//16 support workcode
}TNewRTLog, *PNewRTLog;


typedef struct _TFTRTLog_{
	UDK_U16 EventType;
	char Data[TFTRTLOGSIZE];//36 support workcode
}TTFTRTLog, *PTFTRTLog;

//???RRS????,Henry 2006-08-28
typedef struct _SSR_AttLog_{
	UDK_U16 PIN;
	UDK_U8 PIN2[24];
	UDK_U8 verified;
	UDK_U32 time_second;
	UDK_U8 status;
	UDK_U32 workcode;
	UDK_U8 reserved[4];
}SSR_TAttLog,*SSR_PAttLog;
typedef struct _AttLogx_{
	UDK_U16 PIN;
	UDK_U8 PIN2[MAX_LOG_PIN2_LEN];
	UDK_U8 verified;
	UDK_U32 time_second;
	UDK_U8 status;
	UDK_U32 workcode;
}TAttLogx,*PAttLogx;
//40 byte
typedef struct _SSR_User_{
	UDK_U16 PIN;
	UDK_U8 Privillege;
	char Password[8];
	char Name[24];
	UDK_U8 Card[4];		//??????????��?????ID???????
	UDK_U8 Group;		//????????????,???
	UDK_U16 TimeZones[4];		//???????????��?��???
	//	UDK_U32 PIN2;		//32��?????????????
	char PIN2[24];
} SSR_TUser, *SSR_PUser;
//72 bytes
//???RRS????

//workcode.dat?? 8byte 2006.10.17
//2006-10-17 workcode?? ????
typedef struct _WORKCODE_{
	UDK_U16 WORKID;
	UDK_U32 WORKCODE;
	UDK_U8  Reserver[2];
}TWORKCODE,*PWorkCode;

//add by yuping
//??????????workcode??
typedef struct _Workcode_{
	UDK_U16 PIN;                                //????????0??????�� 2byte
	char Code[MAX_WORKCODE_LEN];            // 9byte 
	char Name[MAX_WORKCODE_NAME_LEN+1];     // 24byte
}TWORKCODE_TFT,*PWorkCode_TFT; 
//---- end ------
typedef struct _TUnlockComb_
{
	UDK_U8 ID;
	UDK_U8 GroupID[5];
	UDK_U8 MemberCount;
	char Reserve[1];
}TUnlockComb, *PUnlockComb;

typedef struct _GROUP_
{
	UDK_U8 ID;
	UDK_U16 TZID[3];
	UDK_U8 VerifyStyle;
}TGroup, *PGroup;

typedef struct _HOLIDAYTZ_
{
	UDK_U16 ID;
	UDK_U8 HDate[2][2];
	UDK_U16 TZID;
}THolidayTz, *PHolidayTz;

typedef struct _ShortKey_{
	UDK_U8 keyID;//1-15
	UDK_U8 keyFun;//0 undefine,1 state,2 workcode,3 sms
	UDK_U8 stateCode;//state only.other -1
	char stateName[STATE_NAME_LEN + 2]; //6????????
	UDK_U16 Time1;//h m
	UDK_U16 Time2;
	UDK_U16 Time3;
	UDK_U16 Time4;
	UDK_U16 Time5;
	UDK_U16 Time6;
	UDK_U16 Time7;              // 14byte(?????????????)
	UDK_U8 autochange;// 1 or 0
}TShortKey, *PShortKey; //32Byte.

#pragma pack(pop)

typedef struct _Template_{
	UDK_U16 Size;
	UDK_U16 PIN;
	char FingerID;
	char Valid;
	char *Template;
}TTemplate, *PTemplate;

#define ZKFPV10_MAX_LEN	1664
typedef struct _TmpX20_{
	UDK_U16 Size;
	UDK_U16 PIN;
	UDK_U8 FingerID;
	UDK_U8 Valid;
	UDK_U8 Template[ZKFPV10_MAX_LEN]; //maximize template length
}TTmpX20, *PTmpX20;
typedef struct tm TTime;



//user->sms
typedef struct _UData_{
	UDK_U16 PIN;        //???????��???
	UDK_U16 SMSID;
}TUData, *PUData;  //4Bytes

//??????
typedef struct _ExtendAttLog_{
	UDK_U32 PIN;
	UDK_U32 time_second;
	UDK_U8 status;
	UDK_U8 verified;
	UDK_U8 reserved[2];
	UDK_U32 workcode;
}TExtendAttLog, *PExtendAttLog;

typedef struct _ExtUser_{
	UDK_U16 PIN;
	UDK_U8 VerifyStyle;
	UDK_U8 reserved[21];
}TExtUser, *PExtUser;

//dsl
typedef struct _CustState_{
	short Identity;		//?????
	UDK_U16 CustState;		//????????
	UDK_U16 UseCustState;	//????????????????1-???? 0-???
}TCustState, *PCustState;

//add by yuping
#ifdef STATE_NAME_LEN
#undef STATE_NAME_LEN
#endif
#define STATE_NAME_LEN 14
#pragma   pack(1)  //?????��1?????? 
typedef struct _OldShortKey_{
	UDK_U8 keyID;//1-15
	UDK_U8 keyFun;//0 undefine,1 state,2 workcode,3 sms
	UDK_U8 stateCode;//state only.other -1
	char stateName[OLD_STATE_NAME_LEN + 2]; //6????????
	UDK_U16 Time1;//h m
	UDK_U16 Time2;
	UDK_U16 Time3;
	UDK_U16 Time4;
	UDK_U16 Time5;
	UDK_U16 Time6;
	UDK_U16 Time7;              // 14byte(?????????????)
	UDK_U8 autochange;// 1 or 0
}TOldShortKey, *POldShortKey; //32Byte.


#pragma   pack() //??????????????

typedef struct _CustVoice_{
	char Identity[10];		//???????
	char Name[20];		//???????
	UDK_U16 UseCustVoice;	//?????????????????1-???? 0-???
}TCustVoice, *PCustVoice;

int gIsEnroll = 0;//9��??????????1,?????????��?????????????????????pin2?pin???????????��??????????????2010.09.16

static TTime *CalcDays(TTime *t)
{
	int y,c;
	y=t->tm_year-2000;
	c=1+(y-1)/4;
	c=c+365*(y-1);  //Total days count
	t->tm_yday=0;
	for(y=1;y<t->tm_mon;y++)
	{
		if(y==2)
		{
			if(t->tm_year%4==0) t->tm_yday+=29; else t->tm_yday+=28;
		}
		else if(y==4 || y==6 || y==9 || y==11)
			t->tm_yday+=30;
		else
			t->tm_yday+=31;
	}
	t->tm_yday+=t->tm_mday;
	c+=t->tm_yday;
	t->tm_wday=(c%7+6)%7;
	//2000-1-1==6
	return t;
}

UDK_U32 EncodeTime(TTime *t)
{
	UDK_U32 tt;
	tt=((t->tm_year%100)*12*31+((t->tm_mon-1)*31)+t->tm_mday-1)*(24*60*60)+
		(t->tm_hour*60+t->tm_min)*60+t->tm_sec;
	return tt;
}

TTime * DecodeTime(UDK_U32 t, TTime *ts)
{
	ts->tm_sec=t % 60;
	t/=60;
	ts->tm_min=t % 60;
	t/=60;
	ts->tm_hour=t % 24;
	t/=24;
	ts->tm_mday=t % 31+1;
	t/=31;
	ts->tm_mon=t % 12+1;
	t/=12;
	ts->tm_year=t+2000;
	CalcDays(ts);
	if(ts->tm_min<0)
		ts->tm_min=0;
	return ts;
}
static char * ReadOption(UDK_HANDLE Handle,const char *Option)
{
	static char s[200] = {0}, *res = NULL;
	unsigned short cmd = 0;
	int i = 0;
	PEmHandle h = (PEmHandle )Handle; 
	cmd = CMD_OPTIONS_RRQ;
	strcpy(s,Option);
	ZEMBPRO_SENDCMD(h->emh,&cmd,s, 200, strlen(Option)+1, 5000);
	if(cmd == CMD_ACK_OK)
	{
		res = s + strlen(Option)+1;			
		return res;
	}
	return NULL;
}

 UDK_HANDLE UDK_API Z_Connect_USB(int DeviceNumber, void* ReadFun, void *Param, int CommKey)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	char *s = NULL;
	int i = 0;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version,VER504);
	h->emh=(PEmHandle)ZEMBPRO_INIT("usbcomm.dll", "", DeviceNumber, 0, (ReadCallBack)ReadFun, Param, CommKey);
	h->BlockSize=1024;	//???????USB????????��?????????????????????????
	h->WaitTimeForACommand=4000;
	h->WaitTimeFor1KData=4000;

	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
		return h;
	}
	else
	{
		if(Z_ERROR_OK==Z_GetFirmwareVersion(h, h->version))
		{
			ConvertMonth(h->version);
			s = ReadOption(h,"~OS");
			if((!s) || !strlen(s) || (!strcmp(s,"NONE")))
				h->DeviceType = 0;
			else
				h->DeviceType = 1;
			//??????��??????
			s = ReadOption(h,"~ExtendFmt");
			if(!s)
				h->ExtendFmt=0;
			else
				h->ExtendFmt=atoi(s);

			//henry 2007-21 modify for events
			//when ver<6.01,reg events auto.
			if(strcmp(h->version,VER601)<0)
			{
				Z_RegEvent(h, 0x7FFF);
			}
			h->RTLogNum=0;

			//dsl.2007.07.04
			s = ReadOption(h,"~Platform");			
			if (s)
			{
				h->IsTFTMachine = 0;
				h->NewSmsFormat = 0;
				if (strstr(s, "TFT"))
				{
					h->IsTFTMachine = 1;
					h->NewSmsFormat = 1;
				}				
			}
			else
			{
				h->NewSmsFormat = 0;
				h->IsTFTMachine = 0;
			}

			//dsl 2007.9.20						
			h->IsNewRTStru = 0;
			if ( (strcmp(h->version, VER61820070807) > 0) && (!h->IsTFTMachine))
			{
				h->IsNewRTStru = 1;
			}		

			s = ReadOption(h,"~ZKFPVersion");
			if(!s || !strlen(s) || !strcmp(s,"NONE"))
				h->EmKeyOptions.ZKFPVersion = 9;
			else
				h->EmKeyOptions.ZKFPVersion = atoi(s);
		}
		else
		{
			Z_Close(h);
			h=NULL;
		}
	}
	return h;
}

//?????��???????��??ComPort??????????PC???��??????
//?????RS232????????��????DeviceNumer?????????????
//??RS485??????????DeviceNumber???????��??
//?????????????????????NULL
 UDK_HANDLE UDK_API Z_Connect_COM(char *ComPort, int DeviceNumber, int BaudRate, void* ReadFun, void *Param, int CommKey, char *Telephone)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	char *s = NULL;
	int i = 0;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version,VER504);
	h->BlockSize=4*1024;//4*1024;????????????????16*1024????????????????????��?????????????????????????
	//dsl	
	if (Telephone)
	{
		if (strlen(Telephone) > 0)
		{
			h->Dialup = 1;
			strcpy(h->Telephone, Telephone);
		}
	}

	if(BaudRate)
	{
		if (h->Dialup == 1)
		{
			h->emh=(PEmHandle)ZEMBPRO_INITEX("rscomm.dll", ComPort,(unsigned short)DeviceNumber, BaudRate, (ReadCallBack)ReadFun, Param, CommKey, h->Telephone);
		}
		else
		{
			h->emh=(PEmHandle)ZEMBPRO_INIT("rscomm.dll", ComPort,(unsigned short)DeviceNumber, BaudRate, (ReadCallBack)ReadFun, Param, CommKey);
		}
		//h->WaitTimeForACommand=115200*1000/BaudRate;
		//h->WaitTimeFor1KData=(115200*1000/BaudRate);
		//?GSM?????????2????3 
		/*	h->WaitTimeForACommand=(115200*1000/BaudRate)*2;		
		h->WaitTimeFor1KData=(115200*1000/BaudRate)*3;*/
		if(BaudRate==9600)
		{
			h->WaitTimeForACommand=h->WaitTimeFor1KData = 12000;
		}
		else if(BaudRate==19200)
		{
			h->WaitTimeForACommand=h->WaitTimeFor1KData = 10000;
		}
		else if(BaudRate==38400)
		{
			h->WaitTimeForACommand=h->WaitTimeFor1KData = 8000;
		}
		else if(BaudRate==57600)
		{
			h->WaitTimeForACommand=h->WaitTimeFor1KData = 6000;
		}
		else if(BaudRate==115200)
		{
			h->WaitTimeForACommand=h->WaitTimeFor1KData = 5000;
		}
		else
		{
			h->WaitTimeForACommand=(115200*1000/BaudRate)*2;		
			h->WaitTimeFor1KData=(115200*1000/BaudRate)*3;
		}
	}
	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
	}
	else
	{
		if(Z_ERROR_OK==Z_GetFirmwareVersion(h, h->version))
		{
			ConvertMonth(h->version);
			s= ReadOption(h,"~OS");
			if(!s || !strcmp(s,"NONE"))
				h->DeviceType = 0;
			else
				h->DeviceType = 1;
			//??????��??????
			s=ReadOption(h,"~ExtendFmt");
			if(!s)
				h->ExtendFmt=0;
			else
				h->ExtendFmt=atoi(s);
			//henry 2007-21 modify for events
			//when ver<6.01,reg events auto.
			if(strcmp(h->version,VER601)<0)
			{
				Z_RegEvent(h, 0x7FFF);
			}
			h->RTLogNum=0;

			//dsl.2007.07.04
			s = ReadOption(h,"~Platform");			
			if (s)
			{
				h->IsTFTMachine = 0;
				h->NewSmsFormat = 0;
				if (strstr(s, "TFT"))
				{
					h->IsTFTMachine = 1;				
					h->NewSmsFormat = 1;				
				}
			}
			else
			{
				h->NewSmsFormat = 0;
				h->IsTFTMachine = 0;
			}

			//dsl 2007.9.20							
			h->IsNewRTStru = 0;
			if ( (strcmp(h->version, VER61820070807) > 0) && (!h->IsTFTMachine))
			{
				h->IsNewRTStru = 1;
			}

			s = ReadOption(h,"~ZKFPVersion");
			if(!s || !strlen(s)|| !strcmp(s,"NONE"))
                h->EmKeyOptions.ZKFPVersion = 9;
			else
				h->EmKeyOptions.ZKFPVersion = atoi(s);
		}
		else
		{
			Z_Close(h);
			h=NULL;
		}
	}

	return h;
}

int getDeviceBaseInfo(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle; 
	char *s = NULL;
	#ifdef _PC
	if(Z_ERROR_OK==Z_GetFirmwareVersion(h, h->version))
	{
		ConvertMonth(h->version);
		s = ReadOption(h,"~OS");
        if(!s || !strlen(s)|| !strcmp(s,"NONE"))
			h->DeviceType = 0;
		else
			h->DeviceType = 1;
		//??????��??????
		s = ReadOption(h,"~ExtendFmt");
		if(!s)
			h->ExtendFmt=0;
		else
			h->ExtendFmt=atoi(s);

		//yuping, 9��???????bug????
		s = ReadOption(h,"ExtendOPLog");
		if(!s)
			h->ExtendOPLog = 0;
		else
			h->ExtendOPLog = atoi(s);
		//end
		//henry 2007-21 modify for events
		//when ver<6.01,reg events auto.
		if(strcmp(h->version,VER601)<0)
		{
			Z_RegEvent(h, 0x7FFF);
		}
		h->RTLogNum=0;
#endif
		//dsl.2007.07.04
		s = ReadOption(h,"~Platform");			
		if (s)
		{
			h->IsTFTMachine = 0;
			h->NewSmsFormat = 0;
			if (strstr(s, "TFT"))
			{
				h->IsTFTMachine = 1;
				h->NewSmsFormat = 1;
			}	
			if(strstr(s, "AK3750"))
			{
				h->libusb_flag = 1;
			}
			if(strstr(s, "3750WIFI"))
			{
				h->wififlag = 1;
				h->libusb_flag = 1;
			}
		}
		else
		{
			h->NewSmsFormat = 0;
			h->IsTFTMachine = 0;
		}
#ifdef _PC
		//dsl 2007.9.20						
		h->IsNewRTStru = 0;
		if ( (strcmp(h->version, VER61820070807) > 0) && (!h->IsTFTMachine))
		{
			h->IsNewRTStru = 1;
		}			
		s = ReadOption(h,"~ZKFPVersion");
		if(!s || !strlen(s)|| !strcmp(s,"NONE"))
			h->EmKeyOptions.ZKFPVersion = 9;
		else
			h->EmKeyOptions.ZKFPVersion = atoi(s);
#endif
		return TRUE;
#ifdef _PC
	}
	else
	{
		return FALSE;
	}
#endif
}

 UDK_HANDLE UDK_API Z_Connect_NETEX(char *IPAddress, int DevicePort, void* ReadFun, void *Param, int CommKey)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	int i = 0;
	if(!h) return NULL;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version, VER504);	//"Ver 5.04 Sep 30 2004"
	h->emh=(PEmHandle)ZEMBPRO_INIT("tcpcomm.dll",IPAddress,(unsigned short)DevicePort,0, (ReadCallBack)ReadFun, Param, CommKey);
	h->WaitTimeForACommand=4000;
	h->WaitTimeFor1KData=4000;
	h->BlockSize=64*1024-64;//the firmware only support 64*1024-sizeof(TCPHeader)
	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
	}else{
		
		if(!getDeviceBaseInfo(h))
		{
			Z_Close(h);
			h=NULL;
		}
		else
		{
			if(h->libusb_flag == 1)
			{
				h->BlockSize = 4088*10;
				h->WaitTimeFor1KData = 1000*20;
				SetBuffLen(h->emh, 512);
			}
			if(h->wififlag)
			{
				h->BlockSize = 2032;
				SetBuffLen(h->emh, 2032);
			}
		}
	}
	
	
	return h;
}

//?????????????��??
//IPAddress??????��??IP?????DevicePort????????��???????
 UDK_HANDLE UDK_API Z_Connect_NET(char *IPAddress, int DevicePort, void* ReadFun, void *Param, int CommKey)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	int i = 0;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version, VER504);	//"Ver 5.04 Sep 30 2004"
	h->emh=(PEmHandle)ZEMBPRO_INIT("comms.dll",IPAddress,(unsigned short)DevicePort,0, (ReadCallBack)ReadFun, Param, CommKey);
	//h->emh=ZEMBPRO_INIT("tcpcomm.dll",IPAddress,(unsigned short)DevicePort,0, (ReadCallBack)ReadFun, Param, CommKey, NULL);
	h->WaitTimeForACommand=4000;
	h->WaitTimeFor1KData=4000;
	h->BlockSize=16*1024;
	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
		return h;
	}
	else
	{
		if(!getDeviceBaseInfo(h))
		{
			Z_Close(h);
			h=NULL;
		}
	}
	return h;
}

void FreeBuffer(UDK_HANDLE Handle)
{
	if(((PEmHandle)Handle)->Buffer && ((PEmHandle)Handle)->BufferLen)
	{
		udk_free(((PEmHandle)Handle)->Buffer);
		((PEmHandle)Handle)->BufferLen=0;
		((PEmHandle)Handle)->Buffer=NULL;
	}
	if(((PEmHandle)Handle)->UserBufferLen && ((PEmHandle)Handle)->UserBuffer)
	{
		udk_free(((PEmHandle)Handle)->UserBuffer);
		((PEmHandle)Handle)->UserBufferLen=0;
		((PEmHandle)Handle)->UserBuffer=NULL;
	}
}

//?????????��
 int UDK_API Z_Close(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle; 
	if(h)
	{		
		if(h->Buffer && h->BufferLen)
		{
			udk_free(h->Buffer);
			h->Buffer=NULL;
			h->TmpBuffer = NULL;
			h->BufferLen=0;
		}
		if(h->UserBufferLen && h->UserBuffer)
		{
			udk_free(h->UserBuffer);
			h->UserBufferLen=0;
			h->UserBuffer=NULL;
		}
		if(h->TmpOpBuf)
		{
			udk_free(h->TmpOpBuf);
			h->TmpOpBuf =NULL;
			h->TmpOpBufLen=0;
			udk_free(h->UserInfoOpBuf);
			h->UserInfoOpBuf=NULL;
			h->UserInfoOpBufLen=0;
			udk_free(h->TmpsBuf);
			h->TmpsBuf=NULL;
			h->TmpsBufLen=0;
			h->IsBatchUpdate =0;
		}
		//dsl 2008.7.26
		if (h->UserIDs)
		{
			udk_free(h->UserIDs);
		}
		ZEMBPRO_CLOSE(h->emh);
		udk_free(h);
		gIsEnroll = 0; //??????????0
		return Z_ERROR_OK;
	}
	else
		return Z_ERROR_NOT_INIT;
}

 int UDK_API Z_RegEvent(UDK_HANDLE Handle, int EventMask)
{/*
 PEmHandle h = (PEmHandle )Handle;
 if(h)
 {
 unsigned short Cmd=CMD_REG_EVENT;
 ZEMBPRO_SENDCMD(h->emh,&Cmd, (char*)&EventMask, 4, 4, h->WaitTimeForACommand);  //
 if(Cmd==CMD_ACK_OK)
 {
 Cmd=CMD_ACK_OK;
 EventMask=-1;
 ZEMBPRO_SENDCMD(h->emh, &Cmd, (char*)&EventMask, 4, 4, 0);  //?????��?????????????????
 return Z_ERROR_OK;
 }
 return Z_ERROR_IO;
 }
 else
 return Z_ERROR_NOT_INIT;*/

	int TmpEventMask = 0; //zhc add TmpEventMask 2010-06-01, ?????��?EventMask????????????????????????????????????????
	PEmHandle h = (PEmHandle )Handle;

	TmpEventMask = EventMask;
	if(h)
	{
		unsigned short Cmd=CMD_REG_EVENT;
		ZEMBPRO_SENDCMD(h->emh,&Cmd, (char*)&TmpEventMask, 4, 4, h->WaitTimeForACommand);  //
		return Cmd==CMD_ACK_OK?Z_ERROR_OK:Z_ERROR_IO;
	}
	else
		return Z_ERROR_NOT_INIT;
}


/*-------------------------------------------
????????
---------------------------------------------*/
//???��?��????????????????????
 int UDK_API Z_ReadLog(UDK_HANDLE Handle, int NewLog)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size, ResSize, SendLen = 1;
	unsigned short Cmd=CMD_ATTLOG_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{ 
		//h->BufferLen=2*1024*1024;
		//h->BufferLen=8*1024*1024;   
		h->BufferLen=40*1024*1024;  //iclock880 ???????????900000??????????33.3M
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}

	if(strcmp(h->version,VER601)>=0 && NewLog)
	{
		Cmd=CMD_READ_NEW;
		h->Buffer[0]=FCT_ATTLOG;
		//dsl 2008.4.17
		if (NewLog == 2)
		{
			*((UDK_U32*)h->Buffer+1) = h->LastCount;
			SendLen = SendLen+7;
		}
		Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer, h->BufferLen, SendLen, h->BlockSize, h->WaitTimeFor1KData);
		if(Cmd==CMD_ACK_OK)
		{
			char d[16];
			Cmd=CMD_UPDATE_READALL;
			d[0]=FCT_ATTLOG;
			ZEMBPRO_SENDCMD(h->emh, &Cmd, d, 16, 1, h->WaitTimeForACommand);
		}
		else if(Cmd==CMD_ACK_ERROR && Size==0)//dsl
		{
			return Z_ERROR_NO_DATA;
		}
	}
	else
		Size=ZEMBPRO_READDATA(h->emh,&Cmd, h->Buffer, h->BufferLen, 0, h->BlockSize, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK && Size > 0)
	{
		h->TmpSize=0; 
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		h->ALogSize=*(int*)(h->Buffer);
		h->ALogBuffer=h->Buffer+4;
		h->cALogBuffer=h->ALogBuffer;
		//_RPT1(0, "TIME0: 0x%X\n", *(int*)(h->ALogBuffer+4));
		return Z_ERROR_OK;
		//???????????????????????
		/*if(h->UserBufferLen || h->UserBuffer)
		{
		udk_free(h->UserBuffer);
		h->UserBufferLen=0;
		h->UserBuffer=NULL;
		}
		if(Z_ReadUserInfo(Handle)==Z_ERROR_OK)
		return Z_ERROR_OK;
		else
		return Z_ERROR_IO;
		*/
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	//	else
	//		return Z_ERROR_IO;

	ResSize=h->BufferLen;
	Size=ZEMBPRO_READDB(h->emh, FCT_ATTLOG, h->BlockSize, h->Buffer, &ResSize);
	if((Size>0) && (ResSize==0))
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		h->ALogSize=Size;
		h->ALogBuffer=h->Buffer;
		h->cALogBuffer=h->ALogBuffer;
		return Z_ERROR_OK;
	}
	else if(Size==0 && ResSize==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;

}

//???��?��????????????????????
 int UDK_API Z_ReadOpLog(UDK_HANDLE Handle, int NewLog)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd=CMD_OPLOG_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(strcmp(h->version,VER504)<0) return Z_ERROR_NO_DATA;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		//h->BufferLen=2*1024*1024;
		h->BufferLen=2*1024*1024*3;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}	
	if(strcmp(h->version,VER601)>=0 && NewLog)
	{
		Cmd=CMD_READ_NEW;
		h->Buffer[0]=FCT_OPLOG;
		Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,
			h->BufferLen, 1, h->BlockSize, h->WaitTimeFor1KData);
		if(Cmd==CMD_ACK_OK)
		{
			char d[16];
			Cmd=CMD_UPDATE_READALL;
			d[0]=FCT_OPLOG;
			ZEMBPRO_SENDCMD(h->emh, &Cmd, d, 16, 1, h->WaitTimeForACommand);
		}
	}
	else
		Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,
		h->BufferLen, 0, h->BlockSize, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL;
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cALogBuffer=NULL;
		h->ALogBuffer=NULL;
		h->ALogSize=0;
		h->OLogSize=*(int*)(h->Buffer);
		h->OLogBuffer=h->Buffer+4;
		h->cOLogBuffer=h->OLogBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

//???��?��????????????????????
 int UDK_API Z_ReadTempData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size, ResSize;
	int reclen = 0;
	unsigned short Cmd=CMD_DB_RRQ;
	unsigned short cmdlargeData=CMD_LARGE_FINGER_MACHINE;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		//??????????????
		h->BufferLen=80*1024*1024;//????iclock880 5??????
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}
	h->TmpSize=0;
	h->TmpBuffer=NULL;
	h->isfingerquick = -1;
	h->Buffer[0]=2;//??????
	ZEMBPRO_SENDCMD(h->emh,&cmdlargeData,NULL,0,0,h->WaitTimeFor1KData);
	if(cmdlargeData == CMD_ACK_OK)
	{
		Cmd = CMD_READ_LARGE_TMP;
		Size = READDATA_PICE_BY_PICE(h->emh,&Cmd,h->Buffer,0,h->Buffer,h->BufferLen,TRUE,50000000,&reclen);
		if(Cmd==CMD_ACK_OK)
		{
			h->OLogSize=0;
			h->OLogBuffer=NULL;
			h->cOLogBuffer=NULL;
			h->cALogBuffer=NULL;
			h->ALogBuffer=NULL;
			h->ALogSize=0;
			h->UDataSize=0;
			h->UDataBuffer=NULL;
			h->cUDataBuffer=NULL; 
			h->TmpSize=Size;
			h->TmpBuffer=h->Buffer;
			h->cTmpBuffer=h->TmpBuffer;
			InitQuickUserTempEx(h);//?????????????
			h->isfingerquick = 1;
			return Z_ERROR_OK;
		}
		return Z_ERROR_IO;
	}
	else
	{
		Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,
			h->BufferLen, (strcmp(h->version,VER504)<0)?0:1, h->BlockSize, h->WaitTimeFor1KData*300);
	}
	if(Cmd==CMD_ACK_OK)
	{
		h->OLogSize=0;
		h->OLogBuffer=NULL;
		h->cOLogBuffer=NULL;
		h->cALogBuffer=NULL;
		h->ALogBuffer=NULL;
		h->ALogSize=0;
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->TmpSize=*(int*)(h->Buffer);
		h->TmpBuffer=h->Buffer+4;
		h->cTmpBuffer=h->TmpBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	//	else
	//		return Z_ERROR_IO;
	ResSize=h->BufferLen;
	Size=ZEMBPRO_READDB(h->emh, 0x2, h->BlockSize, h->Buffer, &ResSize);
	if((Size>0) && (ResSize==0))
	{
		h->OLogSize=0;
		h->OLogBuffer=NULL;
		h->cOLogBuffer=NULL;
		h->cALogBuffer=NULL;
		h->ALogBuffer=NULL;
		h->ALogSize=0;
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->TmpSize=Size;
		h->TmpBuffer=h->Buffer;
		h->cTmpBuffer=h->TmpBuffer;
		return Z_ERROR_OK;
	}
	else if(Size==0 && ResSize==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
	{
		return Z_ERROR_IO;
	}
}

//???��?��???Buffer[0]????????????????????Buffer??, ?????*(int*)Buffer???????????Buffer[4]?????????????
 int UDK_API Z_ReadData(UDK_HANDLE Handle, char *Buffer, int BufferSize)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd=CMD_DB_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;

	Size=ZEMBPRO_READDATA(h->emh,&Cmd,Buffer,
		BufferSize, 1, h->BlockSize, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		return Z_ERROR_OK;
	}
	else
		return Z_ERROR_IO;
}

static void ConvertOldUser(PUserOld Buffer, int Count)
{
	int i,size=Count*sizeof(TUser);
	PUser user=(PUser)udk_malloc(size);
	memset(user,0,size);
	for(i=0;i<Count;i++)
		memcpy(user+i, Buffer+i, sizeof(TUserOld));
	memcpy(Buffer, user, size);
}

//???��?��??????????????????��?
 int UDK_API Z_ReadUserInfo(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size, ResSize;
	unsigned short Cmd;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserBufferLen==0 || h->UserBuffer==NULL)
	{
		//henry ???? ????????????
		//h->UserBufferLen=64*4*1024*4; //???3??????
		h->UserBufferLen=2*1024*1024*3;// ????6M???
		h->UserBuffer=(char*)udk_malloc(h->UserBufferLen);
		memset(h->UserBuffer,0,h->UserBufferLen);
	}
	//Sleep(1000);
	//add by zxz 2013-03-28
	if(h->UserBuffer){
		memset(h->UserBuffer,0,h->UserBufferLen);
		h->UserSize = 0;
	}
	if(h->TmpBuffer){
		memset(h->TmpBuffer,0,h->TmpSize);	//ÐÞ¸´¿ÉÄÜÒý·¢»º³åÇøÒç³öµÄÎÊÌâ
		h->TmpSize = 0;
	}

	Cmd=CMD_USERTEMP_RRQ;
	h->UserBuffer[0]=FCT_USER;
	Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->UserBuffer,
		h->UserBufferLen, (strcmp(h->version,VER504)<0)?0:1, h->BlockSize, h->WaitTimeFor1KData);
	if((Cmd==CMD_ACK_OK) && (Size>0))
	{
		h->UserSize=*(int*)(h->UserBuffer);
		//		h->UserBuffer=h->Buffer+4;
		/*		if(strcmp(h->version,VER504)<0)
		{
		ConvertOldUser((PUserOld)h->UserBuffer, h->UserSize/sizeof(TUserOld));
		}*/
		h->cUserBuffer=h->UserBuffer+4;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	//	else
	//		return Z_ERROR_IO;

	ResSize=h->UserBufferLen;//zl?
	Size=ZEMBPRO_READDB(h->emh, FCT_USER, h->BlockSize, h->UserBuffer, &ResSize);
	if((Size>0) && (ResSize==0))
	{
		h->UserSize=Size;
		h->cUserBuffer=h->UserBuffer;
		return Z_ERROR_OK;
	}
	else if(Size==0 && ResSize==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;

}

int UnpackAttLog(char *buf, PAttLog log)
{
	log->PIN=*(UDK_U16*)buf;
	log->status=(buf[2] >> 5) & 7;
	log->verified=(buf[2] >> 3) & 3;
	if(buf[2] & 4)//short time format
	{
		log->time_second=(UDK_U8)buf[3]+((buf[2] & 3) << 8);
		return AttLogSize1;
	}
	else
	{
		log->time_second=((UDK_U32*)buf)[1];
		return AttLogSize2;
	}
}

PUser SearchUID(UDK_HANDLE Handle, char *UserBuffer, int size, int uid)
{
	int i;
	PEmHandle h = (PEmHandle )Handle;
	UserBuffer+=4;
	if(strcmp(h->version,VER504)<0)
	{
		for(i=0;i<(int)(size/sizeof(TUserOld));i++)
			if(((PUserOld)(UserBuffer))[i].PIN==uid) return (PUser)(((PUserOld)UserBuffer)+i);
	}
	else
		for(i=0;i<(int)(size/sizeof(TUser));i++)
			if(((PUser)(UserBuffer))[i].PIN==uid) return ((PUser)UserBuffer)+i;

	return NULL;
}

PUser SearchPIN2(UDK_HANDLE Handle, char *UserBuffer, int size, int PIN2)
{
	int i;
	PEmHandle h = (PEmHandle )Handle;
	UserBuffer+=4;
	if(strcmp(h->version,VER504)<0) return NULL;
	for(i=0;i<(int)(size/sizeof(TUser));i++)
		if(((PUser)(UserBuffer))[i].PIN2==PIN2) return ((PUser)UserBuffer)+i;
	return NULL;
}

int GetPIN2(UDK_HANDLE Handle, int UserID)
{
	/*PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(strcmp(h->version,VER504)<0) return UserID;
	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
	Z_ReadUserInfo(Handle);
	}
	u=SearchUID(h, h->UserBuffer, h->UserSize, UserID);
	if(u)
	{
	#ifdef PIN2SUPPORT
	if(u->PIN2 && (h->PINWidth>5)) 
	{
	return u->PIN2;
	}
	else 
	#endif
	return UserID;
	}
	else
	return UserID;*/
	//henry modify to new 2007-01-09
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(strcmp(h->version,VER504)<0) return UserID;
	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	u=SearchUID(h, h->UserBuffer, h->UserSize, UserID);
	if(u)
	{
		if(u->PIN2) 
		{
			return u->PIN2; 
		}
		else 
			return UserID;
	}
	else
		return UserID;
}

 int UDK_API Z_GetUserPIN2(UDK_HANDLE Handle, int UserID)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(strcmp(h->version,VER504)<0) return -2;
	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	u=SearchUID(h, h->UserBuffer, h->UserSize, UserID);
	if(u)
	{
		return u->PIN2; 
	}
	else
		return -1;
}

int GetPIN1(UDK_HANDLE Handle, int PIN2)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(strcmp(h->version,VER504)<0) return PIN2;
	if((h->PINWidth<=5) && (PIN2<(WORD)0xFFFF)) return PIN2;
	if(h->UserBuffer==NULL || h->UserBufferLen==0 || 1 == gIsEnroll)
	{
		Z_ReadUserInfo(Handle);
	}
	u=SearchPIN2(h, h->UserBuffer, h->UserSize, PIN2);
	if(u)
	{
		return u->PIN; 
	}
	else 	
	{
		/*henry modify for batch update user information and can not add user info into buffer,so it can 
		not get user PIN. 2007-3-7 */

		if(h->PINWidth<=5)
			return PIN2;
		else
		{
			if(h->IsBatchUpdate)
			{
				u=SearchPIN2(h,h->BatchTmpUserInfo, h->BatchTmpSize,PIN2);
				if(u) return u->PIN; else return PIN2;
			}
			else
				return PIN2;
		}
	}
}

 int UDK_API Z_GetUserID(UDK_HANDLE Handle, int PIN2)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(strcmp(h->version,VER504)<0) return -2;
	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	u=SearchPIN2(h, h->UserBuffer, h->UserSize, PIN2);
	if(u)
	{
		return u->PIN; 
	}
	else
		return -1;
}

PUser SearchCard(UDK_HANDLE Handle, char *UserBuffer, int size, char *Card)
{
	int i;
	PEmHandle h = (PEmHandle )Handle;
	if(strcmp(h->version,VER504)<0) return NULL;
	UserBuffer+=4;
	for(i=0;i<(int)(size/sizeof(TUser));i++)
		if(memcmp(((PUser)(UserBuffer))[i].Card, Card, 5)==0) return ((PUser)UserBuffer)+i;
	return NULL;
}


//???????????????????????????????1????????????????????????????????????
 int UDK_API Z_GetLog(UDK_HANDLE Handle, int *PIN, char *VerifyMode, char *State,
										int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second)
{
	PEmHandle h = (PEmHandle )Handle;
	TAttLog log; 
	TExtendAttLog extlog;
	int len;
	TTime t;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->ALogSize==0 || h->Buffer==NULL)
	{//??��??????????????????
		if(Z_ReadLog(Handle, TRUE)!=Z_ERROR_OK) return Z_ERROR_IO;
	}
	if(h->ALogSize==0 || h->ALogBuffer==NULL) return Z_ERROR_NO_DATA;
	if(h->cALogBuffer<h->ALogBuffer+h->ALogSize)
	{
		if(!h->ExtendFmt)
		{
			len=UnpackAttLog(h->cALogBuffer, &log);
			if(log.time_second<0)
			{
				log.time_second+=147527411;
			}
			h->cALogBuffer+=len;
			if(log.PIN==0xFFFF || h->cALogBuffer>h->Buffer+h->BufferLen) return Z_ERROR_NO_DATA;
			//*PIN=GetPIN2(h, log.PIN);
			//henry modify ,????��???????????5????????PIN2.
			if (h->PINWidth>5)
				*PIN=GetPIN2(h, log.PIN);
			else
				*PIN=log.PIN;
			*VerifyMode=log.verified;
			*State=log.status;
			if(len==AttLogSize1)
				log.time_second += h->LastTime;
			else
				h->LastTime=log.time_second;
			DecodeTime(log.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
		}else
		{
			len=sizeof(TExtendAttLog);
			memcpy(&extlog,h->cALogBuffer,len);
			h->cALogBuffer+=len;
			*PIN=extlog.PIN;
			*VerifyMode=extlog.verified;
			*State=extlog.status;
			DecodeTime(extlog.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
		}
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}

//??????????????????????????????????1????????????????????????????????????
 int UDK_API Z_GetExtLog(UDK_HANDLE Handle, int *PIN, char *VerifyMode, char *State,
										   int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second,int *WorkCode, int *Reserved)
{
	PEmHandle h = (PEmHandle )Handle;
	TAttLog log;
	TExtendAttLog extlog;
	int len;
	TTime t;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->ALogSize==0 || h->Buffer==NULL)
	{//??��??????????????????
		if(Z_ReadLog(Handle, TRUE)!=Z_ERROR_OK) return Z_ERROR_IO;
	}
	if(h->ALogSize==0 || h->ALogBuffer==NULL) return Z_ERROR_NO_DATA;
	if(h->cALogBuffer<h->ALogBuffer+h->ALogSize)
	{
		if(!h->ExtendFmt)
		{
			len=UnpackAttLog(h->cALogBuffer, &log);
			if(log.time_second<0)
			{
				log.time_second+=147527411;
			}
			h->cALogBuffer+=len;
			if(log.PIN==0xFFFF || h->cALogBuffer>h->Buffer+h->BufferLen) return Z_ERROR_NO_DATA;
			//*PIN=GetPIN2(h, log.PIN);
			if (h->PINWidth>5)
				*PIN=GetPIN2(h, log.PIN);
			else
				*PIN=log.PIN;
			*VerifyMode=log.verified;
			*State=log.status;
			if(len==AttLogSize1)
				log.time_second += h->LastTime;
			else
				h->LastTime=log.time_second;
			DecodeTime(log.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
			//???????????????????0
			*WorkCode=0;
			*Reserved=0;
		}else
		{
			len=sizeof(TExtendAttLog);
			memcpy(&extlog,h->cALogBuffer,len);
			h->cALogBuffer+=len;
			*PIN=extlog.PIN;
			*VerifyMode=extlog.verified;
			*State=extlog.status;
			DecodeTime(extlog.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
			*WorkCode=extlog.workcode;
			*Reserved=*(UDK_U16*)(extlog.reserved);
		}
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}

typedef struct _OPLog_{
	UDK_U16 Admin;			//2
	UDK_U8 OP;			//2
	UDK_U32 time_second;	//4
	UDK_U16 Users[4];		//2*4
}TOPLog, *POPLog;

//add by xisy 2011-06-08
typedef struct _OPLogEx_{
	UDK_U16 Admin;			//2
	UDK_U8 OP;			//2
	UDK_U32 time_second;	//4
	UDK_U16 Users[4];		//2*4
	char PIN2[24];
}TOPLogEx, *POPLogEx;
//end add by xisy

//add by yuping, oplog 9��??bug
#pragma pack(push)
#pragma pack(1)
typedef struct _ExtOPLog_{
	UDK_U32 Admin;              //4?????��???????????pin(?????????pin)
	UDK_U8 OP;                //1?????��?????????
	UDK_U8 reserved;          //1
	UDK_U32 time_second;     //4?????��????????
	UDK_U32 User;               //4?????��???????????????pin?????��??????�p????????0???�C??????????
	UDK_U16 Params[3];          //2*3 //???��??????��???????
}TExtOPLog, *PExtOPLog; //total 20bytes, 64K flash max 3276logs, //16, 4096
#pragma pack(pop)
//add end

//*add by yuping
 int UDK_API Z_GetOpLog(UDK_HANDLE Handle, int *PIN, int *OP, int *Params,
										  int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second)
{
	PEmHandle h = (PEmHandle )Handle;
	TTime t = {0};

	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(strcmp(h->version, VER504) < 0)
	{
		return Z_ERROR_NO_DATA;
	}
	if(h->OLogSize == 0 || h->Buffer == NULL)
	{
		//??��??????????????????
		if(Z_ReadOpLog(Handle, TRUE) != Z_ERROR_OK)
		{
			return Z_ERROR_IO;
		}
	}
	if(h->OLogSize==0 || h->OLogBuffer==NULL)
	{
		return Z_ERROR_NO_DATA;
	}

	if(h->cOLogBuffer < (h->OLogBuffer + h->OLogSize))
	{
		if(!h->ExtendOPLog)
		{
			POPLog log = (POPLog)h->cOLogBuffer;
			h->cOLogBuffer += sizeof(TOPLog);
			if((log->Admin == 0xFFFF) || (h->cOLogBuffer > h->Buffer + h->BufferLen))
			{
				return Z_ERROR_NO_DATA;
			}

			*PIN = log->Admin;
			*OP = log->OP;
			Params[0] = log->Users[0];
			Params[1] = log->Users[1];
			Params[2] = log->Users[2];
			Params[3] = log->Users[3];
			DecodeTime(log->time_second, &t);
			*Year = t.tm_year;
			*Month = t.tm_mon;
			*Day = t.tm_mday;
			*Hour = t.tm_hour;
			*Minute = t.tm_min;
			*Second = t.tm_sec;
			//?????options????
			if(h->PINWidth > 5)
			{
				//MessageBox(NULL, "Options Setting Error!", NULL, MB_OK);
				//return Z_ERROR_NO_DATA;
				*PIN=GetPIN2(h, log->Admin);
				if (log->Users[0] && (log->OP == 30 || log->OP == 6 || log->OP ==7 || log->OP ==8 || log->OP ==9 || log->OP ==10 || log->OP == 11 || log->OP == 12))//dsl 2007.11.19
				{
					Params[0] = GetPIN2(Handle, log->Users[0]);
				}				
				else
				{
					Params[0]=log->Users[0];
				}
			}
		}
		else
		{
			TExtOPLog *pExtOpLog = (TExtOPLog *)h->cOLogBuffer;
			h->cOLogBuffer += sizeof(TExtOPLog);
			if(h->cOLogBuffer > h->Buffer + h->BufferLen)
			{
				return Z_ERROR_NO_DATA;
			}

			*PIN = pExtOpLog->Admin;
			*OP = pExtOpLog->OP;
			Params[0] = pExtOpLog->User;
			Params[1] = pExtOpLog->Params[0];
			Params[2] = pExtOpLog->Params[1];
			Params[3] = pExtOpLog->Params[2];
			DecodeTime(pExtOpLog->time_second, &t);
			*Year = t.tm_year;
			*Month = t.tm_mon;
			*Day = t.tm_mday;
			*Hour = t.tm_hour;
			*Minute = t.tm_min;
			*Second = t.tm_sec;
		}
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}
//add end*/

/*/*********************** yuping del *******************************************
 int UDK_API Z_GetOpLog(UDK_HANDLE Handle, int *PIN, int *OP, int *Params,
int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second)
{
PEmHandle h = (PEmHandle )Handle;
TTime t;
if(NULL==h)	return Z_ERROR_NOT_INIT;
if(strcmp(h->version,VER504)<0) return Z_ERROR_NO_DATA;
if(h->OLogSize==0 || h->Buffer==NULL)
{//??��??????????????????
if(Z_ReadOpLog(Handle, TRUE)!=Z_ERROR_OK) return Z_ERROR_IO;
}
if(h->OLogSize==0 || h->OLogBuffer==NULL) return Z_ERROR_NO_DATA;
if(h->cOLogBuffer<h->OLogBuffer+h->OLogSize)
{
POPLog log;
log=(POPLog)h->cOLogBuffer;
h->cOLogBuffer+=sizeof(TOPLog);
if(log->Admin==0xFFFF || h->cOLogBuffer>h->Buffer+h->BufferLen) return Z_ERROR_NO_DATA;
if(h->PINWidth<=5)
*PIN=log->Admin;
else
*PIN=GetPIN2(h, log->Admin);
*OP=log->OP;
if(Params)
{
//dsl 2007.8.3. 9��???Params[0]?��???????PIN??????????BUG
if(h->PINWidth <= 5)
{
Params[0]=log->Users[0];
}
else
{
//30????????6?????????Params[3]????????? Params[0]????????
if (log->Users[0] && (log->OP == 30 || log->OP == 6 || log->OP ==7 || log->OP ==8 || log->OP ==9 || log->OP ==10 || log->OP == 11 || log->OP == 12))//dsl 2007.11.19
{
Params[0] = GetPIN2(Handle, log->Users[0]);
}				
else
{
Params[0]=log->Users[0];
}
}
Params[1]=log->Users[1];
Params[2]=log->Users[2];
Params[3]=log->Users[3];
}
DecodeTime(log->time_second, &t);
*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
}
else
return Z_ERROR_NO_DATA;
return Z_ERROR_OK;
}
*************************** end *******************************************/

#define PRI_VALIDUSER	0
#define PRI_INVALIDUSER 1
#define PRI_VALIDBIT	1
#define PRI_ENROLL	2
#define PRI_OPTIONS 4
#define PRI_SUPERVISOR 8
#define ISADMIN(p)	(((p) & ~PRI_VALIDBIT)!=0)

#define PRIVILLEGE0 PRI_VALIDUSER
#define PRIVILLEGE1 (PRI_ENROLL)
#define PRIVILLEGE2 (PRI_ENROLL|PRI_OPTIONS)
#define PRIVILLEGE3 (PRI_ENROLL|PRI_OPTIONS|PRI_SUPERVISOR)

#define ISINVALIDUSER(user) (((user).Privillege & PRI_VALIDBIT)!=PRI_VALIDUSER)

int SetUserTZValue(PUser User, int *TZs)
{
	int value=0, i=0;
	int UseGroup=((TZs==NULL)||(TZs[0]==-1));
	if(UseGroup)
		User->Group &= 0xF;
	else
	{
		while(i<3)
		{
			if(TZs[i]==0) break;
			value|=((TZs[i] & 0x3f)<<(i*6)); //6 BIT Per TimeZone
			i++;
		}
		User->TimeZones=value & 0xFFFF;
		User->Group=(User->Group & 0xF) | (((value>>16) & 0x0F) << 4) | (UseGroup?0:0x80);
	}
	return i;
}

int GetUserTZValue(PUser User, int *TZs)
{
	int value=0;
	if((User->TimeZones==0) && (0==(User->Group & 0xF0))) //Use Group Default
	{
		TZs[0]=-1;
		return -1;
	}
	TZs[0]=User->TimeZones & 0x3F;
	TZs[1]=User->TimeZones>>6 & 0x3F;
	TZs[2]=(User->TimeZones>>12)+16*(0x3 & (User->Group>>4));
	if(TZs[0]==0) return 0;
	if(TZs[1]==0) return 1;
	if(TZs[2]==0) return 2;
	if(TZs[2]) TZs[3]=0;
	return 3;
}

//?????????????????????????????????1????????????????????????????????????
 int UDK_API Z_GetUserInfo(UDK_HANDLE Handle, int *PIN, char *Name,  int *Privillege,
											 int *Valid, char *Password, char *Card, int *PIN2, int *Group, int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return Z_ERROR_IO;
	}
	if(h->UserSize==0 || h->UserBuffer==NULL) return Z_ERROR_NO_DATA;
	if(h->cUserBuffer<h->UserBuffer+h->UserSize)
	{
		PUser u=(PUser)(h->cUserBuffer);
		if(strcmp(h->version,VER504)<0)
			h->cUserBuffer=((char*)u)+sizeof(TUserOld);
		else
			h->cUserBuffer=(char*)(u+1);
		*PIN=u->PIN;
		if(Name) strncpy(Name,u->Name, 8); Name[8]=0;
		if(Privillege)
		{
			/*if((PRIVILLEGE3 & u->Privillege)==PRIVILLEGE3) *Privillege=3;
			else if((PRIVILLEGE2 & u->Privillege)==PRIVILLEGE2) *Privillege=2;
			else if((PRIVILLEGE1 & u->Privillege)==PRIVILLEGE1) *Privillege=1;
			else *Privillege=u->Privillege;*/
			if (!h->bNewFirmware)
			{
				if(((u->Privillege)>>1)==7)
				{
					*Privillege=3;
				}else if(((u->Privillege)>>1)==5)
				{
					*Privillege=4;
				}else if(((u->Privillege)>>1)==3)
				{
					*Privillege=2;
				}else if(((u->Privillege)>>1)==1) 
				{
					*Privillege=1;
				}else if(((u->Privillege)>>1)==0) 
				{
					*Privillege=0;
				}else if (u->Privillege == 255) //?????????
				{
					*Privillege = -1;
				}else
				{
					*Privillege=u->Privillege;
				}
			}
			else
			{
				*Privillege=u->Privillege;
			}
			
		}
		if(Valid) *Valid=!(u->Privillege & 1);
		if(Password) strncpy(Password, u->Password, 5); Password[5]=0;
		if(strcmp(h->version,VER504)<0)
		{
			*Group=1;
			*TZs=-1;
			*PIN2=0;
			memset(Card,0,5); 
		}
		else
		{
			if(Card) memcpy(Card, u->Card, sizeof(u->Card));
			/*#ifdef PIN2SUPPORT
			if(PIN2 && h->PINWidth>5) 
			*PIN2=u->PIN2;
			else
			#endif
			*PIN2=u->PIN;}*/
			//henry add
			if(PIN2) *PIN2=u->PIN2;
			if(Group) *Group=u->Group & 0x0f;
			if(TZs) GetUserTZValue(u, TZs);
		}
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}

 int UDK_API Z_QueryUserByPIN2(UDK_HANDLE Handle, int PIN2)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return Z_ERROR_IO;
	}

	u=SearchPIN2(h, h->UserBuffer, h->UserSize, PIN2);
	if(!u) return Z_ERROR_NO_DATA;
	return u->PIN;
}

int QueryFreeUserID(UDK_HANDLE Handle, int PIN2)
{
	int i,size;
	PEmHandle h = (PEmHandle )Handle;
	char *UserBuffer;
	char *UserIDs;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return 1;
	}
	UserBuffer=h->UserBuffer+4;
	UserIDs=(char*)udk_malloc(0x10000);
	memset(UserIDs, 0, 0x10000);
	size=h->UserSize;
	if(strcmp(h->version,VER504)<0)
	{
		for(i=0;i<(int)(size/sizeof(TUserOld));i++)
			UserIDs[((PUserOld)(UserBuffer))[i].PIN]=1;
	}
	else
		for(i=0;i<(int)(size/sizeof(TUser));i++)
			UserIDs[((PUser)(UserBuffer))[i].PIN]=1;
	//henry modify the query user id from batch buffer.
	if(h->IsBatchUpdate)
	{
		UserBuffer=h->BatchTmpUserInfo+4;
		//dsl 2007.11.23.//??????????????????????9��??????????????????????????ID????????1???????size=h->BatchTmpSize
		size = h->BatchTmpSize;
		for(i=0;i<(int)(size/sizeof(TUser));i++)
			UserIDs[((PUser)(UserBuffer))[i].PIN]=1;
	}

	i=0;
	if(PIN2<0xFFFF)	
		if(UserIDs[PIN2]==0)		
			i=PIN2;	
	if(i==0)
	{
		for(i=1;i<0xFFFF;i++)
		{
			if(UserIDs[i]==0)
			{
				break;
			}
		}
	}
	udk_free(UserIDs);
	return i;
}

 int UDK_API Z_QueryUserByCard(UDK_HANDLE Handle, char *Card)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserSize==0 || h->Buffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return Z_ERROR_IO;
	}

	u=SearchCard(h, h->UserBuffer,h->UserSize,Card);
	if(!u) return Z_ERROR_NO_DATA;
	return u->PIN;
}

 int UDK_API Z_QueryUserInfo(UDK_HANDLE Handle, int PIN, char *Name,  int *Privillege,
											   int *Valid, char *Password, char *Card, int *PIN2, int *Group, int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	PUser u;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return Z_ERROR_IO;
	}

	if(PIN==0)
	{
		u=SearchPIN2(h, h->UserBuffer,h->UserSize, *PIN2);
	}
	else
		u=SearchUID(h, h->UserBuffer,h->UserSize, PIN);
	if(!u) return Z_ERROR_NO_DATA;

	if(Name) strncpy(Name,u->Name, 8); Name[8]=0;
	if(Privillege)
	{
		/*if((PRIVILLEGE3 & u->Privillege)==PRIVILLEGE3) *Privillege=3;
		else if((PRIVILLEGE2 & u->Privillege)==PRIVILLEGE2) *Privillege=2;
		else if((PRIVILLEGE1 & u->Privillege)==PRIVILLEGE1) *Privillege=1;
		else *Privillege=0;*/

		if (!h->bNewFirmware)
		{
			if(((u->Privillege)>>1)==7)
			{
				*Privillege=3;
			}else if(((u->Privillege)>>1)==5)
			{
				*Privillege=4;
			}else if(((u->Privillege)>>1)==3)
			{
				*Privillege=2;
			}else if(((u->Privillege)>>1)==1) 
			{
				*Privillege=1;
			}else if(((u->Privillege)>>1)==0) 
			{
				*Privillege=0;
			}else if (u->Privillege == 255) //?????????
			{
				*Privillege = -1;
			}else
			{
				*Privillege=u->Privillege;
			}
		}
		else
		{
			*Privillege=u->Privillege;
		}
		

	}
	if(Valid) *Valid=!(u->Privillege & 1);
	if(Password) strncpy(Password, u->Password, 5); Password[5]=0;
	if(strcmp(h->version,VER504)<0)
	{
		*Group=1;
		*TZs=-1;
		*PIN2=0;
		memset(Card,0,5);
	}
	else
	{
		if(Card) memcpy(Card, u->Card, sizeof(u->Card));
		if(PIN2) *PIN2=u->PIN2;
		if(Group) *Group=u->Group & 0x0f;
		if(TZs) GetUserTZValue(u, TZs);
	}
	return Z_ERROR_OK;
}

PTemplate UnpackTmp(char *a, PTemplate tmp)
{
	if(tmp)
	{
		tmp->FingerID=((UDK_U8*)a)[4];
		tmp->Size=(*(UDK_U16*)a)-6;
		tmp->Template=(char*)a+6;
		tmp->PIN=((UDK_U16*)a)[1];
		tmp->Valid=((UDK_U8*)a)[5];
		return tmp;
	}
	return NULL;
}

//????????????��????????????�^
//FingerIndex?????????????????????????10??????????��?1-10
//TempData???????????????????????????��???��??Size?????
//?????????�?????????????????????TempData???��?2K???
//???????????????��????????????????????????0??????????????
 int UDK_API Z_GetUserTmp(UDK_HANDLE Handle, int PIN, int FingerIndex, 
											char *TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTEMP_RRQ;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(WORD*)TmpData=GetPIN1(h, PIN);
	TmpData[2]=FingerIndex;
	*Size=ZEMBPRO_SENDCMD(h->emh, &cmd, TmpData, *Size, 3, h->WaitTimeFor1KData);
	if(cmd==CMD_ACK_ERROR)
	{
		return Z_ERROR_NO_DATA;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?????????????�^
//???????????????0???????????1???????????
 int UDK_API Z_DelUserTmp(UDK_HANDLE Handle, int PIN, int FingerIndex)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DELETE_USERTEMP;
	char buf[6];
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(WORD*)buf=GetPIN1(h, PIN);
	buf[2]=FingerIndex;
	if(h->IsBatchUpdate){
		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf;	//???ID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=(char)FingerIndex;		//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=-1;	//Offset
		h->TmpOpBufLen+=8;
		return Z_ERROR_OK;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 3, 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?????????????
//????????????????0???????????1???????????
 int UDK_API Z_DelUser(UDK_HANDLE Handle, int PIN)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DELETE_USER;
	int i;
	PUser user=(PUser)udk_malloc(sizeof(TUser));

	int TmpPIN = 0; //zhc add TmpPIN 2010-06-01, ?????��?PIN????????????????????????????????????????

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	PIN=GetPIN1(h, PIN);
	if(h->IsBatchUpdate){
		user->PIN =PIN;
		(h->UserInfoOpBuf+h->UserInfoOpBufLen)[0]=0;	//???????
		memcpy(h->UserInfoOpBuf+h->UserInfoOpBufLen+1,user,sizeof(TUser));//??????
		h->UserInfoOpBufLen+=sizeof(TUser)+1;

		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=PIN;	//???ID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=0xFF;						//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=-1;	//Offset
		h->TmpOpBufLen+=8;
		return Z_ERROR_OK;
	}

	TmpPIN = PIN; //add by zhc 2010-06-01
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&TmpPIN, 0, 2,16000+h->WaitTimeForACommand);
	//if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;//dsl 2008.10.24 ???????????????????????????i=2,??
	//????
	if(cmd==CMD_ACK_ERROR) return Z_ERROR_NO_DATA;//dsl 2008.10.24
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//???????????????????????????????????
//?????????1???????????
 int UDK_API Z_SetUserInfo(UDK_HANDLE Handle, int PIN, char *Name,  int Privillege,
											 int Valid, char *Password, char *Card, int PIN2, int Group, int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USER_WRQ;
	TUser u; 

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(PIN>=65535)
	{
		return Z_ERROR_LENOVER; //ERROR_SIZE
	}
	memset((void*)&u,0,sizeof(TUser));

	if(strcmp(h->version,VER504)<0)
	{
		char *buf=(char*)&u;
		*(WORD*)buf=PIN;
		memcpy(buf+2,Name,8);
		memcpy(buf+2+8,Password, 5);
		if(!h->bNewFirmware)
		{
			if(Privillege==2) Privillege=PRIVILLEGE2;
			else if(Privillege==1) Privillege=PRIVILLEGE1;
			else if(Privillege==3) Privillege=PRIVILLEGE3;
		}
		
		buf[2+8+5]=Privillege | (Valid==0);
		buf[2+8+5+1]=Valid; 
		ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 2+8+5+1+1, 4*h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		if(h->UserBuffer)
		{//??????????????????????
			h->UserSize=0;
			udk_free(h->UserBuffer);
			h->UserBuffer=NULL;
			h->UserBufferLen=0; 
		}
	}
	else
	{
		PUser user=NULL;
		if(h->UserBuffer==NULL||h->UserBufferLen==0) Z_ReadUserInfo(Handle);
		if(PIN==0)
		{
			user=SearchPIN2(Handle, h->UserBuffer, h->UserSize, PIN2);
			//henry modify at 2007-3-16
			if(user==NULL&&h->IsBatchUpdate)
				user=SearchPIN2(Handle, h->BatchTmpUserInfo, h->BatchTmpSize, PIN2);
			if(user==NULL)
				PIN=QueryFreeUserID(Handle, PIN2);
			else
				PIN=user->PIN;
		}
		else if(PIN2==0)
			user=SearchUID(Handle, h->UserBuffer, h->UserSize, PIN);
		u.PIN=PIN;
		if(Name) memcpy(u.Name,Name,8);
		if(Password) memcpy(u.Password,Password, 5);
		if(!h->bNewFirmware)
		{
			if(Privillege==2) Privillege=PRIVILLEGE2;
			else if(Privillege==1) Privillege=PRIVILLEGE1;
			else if(Privillege==3) Privillege=PRIVILLEGE3;
		}
		u.Privillege=Privillege | (Valid==0);
		u.PIN2=PIN2;
		if(PIN2==0 && user)
		{
			u.PIN2=user->PIN2;
			if(u.PIN2==0)
				u.PIN2=PIN;
		}
		if(Card) memcpy(u.Card, Card, sizeof(u.Card));
		u.Group=Group & 0x0f;
		if(TZs) SetUserTZValue(&u, TZs);

		if(h->IsBatchUpdate){
			//henry modify 9 dight for batch upload model 2007-3-7
			if(user==NULL)
			{	//memcpy
				//dsl 2007.11.23
				//if(h->BatchTmpSize==0) 
				//	memcpy(h->BatchTmpUserInfo+h->BatchTmpSize+4, &u,sizeof(TUser));// ?????????????
				//else
				//	memcpy(h->BatchTmpUserInfo+h->BatchTmpSize, &u,sizeof(TUser));// ??????????????
				memcpy(h->BatchTmpUserInfo+h->BatchTmpSize+4, &u,sizeof(TUser));// ?????????????
				h->BatchTmpSize+=sizeof(TUser);
			}
			*(UDK_U8*)(h->UserInfoOpBuf+h->UserInfoOpBufLen)=2;	//???????
			memcpy(h->UserInfoOpBuf+h->UserInfoOpBufLen+1,&u,sizeof(TUser));//??????
			h->UserInfoOpBufLen+=sizeof(TUser)+1;
			/*if(NULL==user) 
			{
			h->UserSize+=sizeof(TUser);
			user=((PUser)(h->UserBuffer+4))+(h->UserSize/sizeof(TUser)-1);
			memcpy(user, &u, sizeof(TUser));
			} */
			return Z_ERROR_OK;
		}
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&u, sizeof(TUser), sizeof(TUser), 2000+h->WaitTimeForACommand);
		if(cmd==CMD_ACK_OK)
		{
			if(NULL==user) 
			{
				h->UserSize+=sizeof(TUser);
				user=((PUser)(h->UserBuffer+4))+(h->UserSize/sizeof(TUser)-1);
			}
			memcpy(user, &u, sizeof(TUser));
		}
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

//?????????????????
//?��???????????????????????????1??????????????????0???????????
//??????????????????10?
 int UDK_API Z_AppendUserTmp(UDK_HANDLE Handle, int PIN, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_APPEND_USERTEMP;
	char buf[2048];
	int i,Size;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset(buf,0,2048);
	Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+13));
	if(Size>1024-(8+5))
	{
		Size=SetBiokeyTemplateLen((UDK_U8*)TmpData, 1024-(8+5));
		if(Size==0)
			return Z_ERROR_SIZE;
	}
	if(Size<50) return Z_ERROR_SIZE;
	PIN=GetPIN1(h, PIN);
	*(WORD*)buf=PIN;
	buf[2]=(char)0xFF;
	*(UDK_U16*)(buf+11)=Size;
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, Size+13, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) 
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else
			return Z_ERROR_IO;
	}

	if(h->UserBuffer)
	{//??????????????????????
		h->UserSize=0;
		udk_free(h->UserBuffer);
		h->UserBuffer=NULL;
		h->UserBufferLen=0;
	}
	return Z_ERROR_OK;
}

//?????????????????
//?��???????????????????????????1??????????????????0???????????
//??????????????????10?
 int UDK_API Z_SetUserTmp(UDK_HANDLE Handle, int PIN, int FingerIndex, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTEMP_WRQ;
	char buf[2048];
	int i,Size;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset(buf,0,2048);

	Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+5));
	if(Size>1024-(8+5))
	{
		Size=SetBiokeyTemplateLen((UDK_U8*)TmpData, 1024-(8+5));
		if(Size==0)
			return Z_ERROR_SIZE;
	}
	if(Size<50) return Z_ERROR_SIZE;

	*(WORD*)buf=GetPIN1(h, PIN);
	buf[2]=(char)FingerIndex;
	*(UDK_U16*)(buf+3)=Size;
	if(h->IsBatchUpdate){
		if(h->IsForceUpdate)
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=2;
		else
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=1;//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf; //UserID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=(char)FingerIndex;	//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=h->TmpsBufLen;//Offset
		h->TmpOpBufLen+=8;

		*(UDK_U16*)(h->TmpsBuf+h->TmpsBufLen)=Size;	//??�??
		memcpy(h->TmpsBuf+h->TmpsBufLen+2,buf+5,Size);//???
		h->TmpsBufLen+=Size+2;								//??????????
		return Z_ERROR_OK;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, Size+5, 1000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

//????????????????????��??????
//??????????????PIN?��?????????????????????????>0????????0
 int UDK_API Z_TestUserTmp(UDK_HANDLE Handle, int *PIN, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short Size, cmd=CMD_TEST_TEMP;
	char buf[2048];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset(buf,0,2048);
	Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)buf);
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 1024, Size, 5000);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	if(*buf)
	{
		if(h->PINWidth<=5)
			*PIN=*(WORD*)buf;
		else
			*PIN=GetPIN2(h, *(WORD*)buf);
		return Z_ERROR_OK;
	}
	else
		return Z_ERROR_NO_DATA;	
}

//????��?��??????????
 int UDK_API Z_ClearData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_DATA;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 20 * 60 *1000 * 500);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;	
	if(h->Buffer)
	{//??????????????????????
		udk_free(h->Buffer);
		h->Buffer=NULL;
		h->TmpBuffer = NULL;
	}
	if(h->UserBuffer)
	{//??????????????????????
		udk_free(h->UserBuffer);
		h->UserBuffer = NULL;
		h->UserSize = 0;
		h->UserBufferLen = 0;
	}
	h->TmpSize=0;
	return Z_ERROR_OK;
}
/*?????????
//??????
#define FCT_ATTLOG (UDK_U8)1
//??????
#define FCT_FINGERTMP (UDK_U8)2
//??????
#define FCT_OLDUSER (UDK_U8)3
//???????
#define FCT_OPLOG (UDK_U8)4
//??????
#define FCT_USER (UDK_U8)5
//??????????
#define FCT_UDATA (UDK_U8)6*/
 int UDK_API Z_ClearDataEx(UDK_HANDLE Handle,int FCT_id)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_DATA;
	char fct_id=FCT_id;
	if(fct_id<1 || fct_id>5) return Z_ERROR_PARAM;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, &fct_id, 1, 1, 3000+h->WaitTimeForACommand);
	if(h->Buffer)
	{//??????????????????????
		udk_free(h->Buffer);
		h->Buffer=NULL;
		h->TmpBuffer = NULL;
	}
	if((FCT_id == FCT_USER) && (h->UserBuffer))
	{//??????????????????????
		udk_free(h->UserBuffer);
		h->UserBuffer = NULL;
		h->UserBufferLen = 0;
		h->UserSize = 0;
	}
	h->TmpSize=0;
	return Z_ERROR_OK;
}

//????��?��??????????
 int UDK_API Z_ClearAdministrators(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_ADMIN;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 2000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	if(h->UserBuffer)
	{//??????????????????????
		udk_free(h->UserBuffer);
		h->UserBuffer=NULL;
		h->UserBufferLen=0;
		h->UserSize=0;
	}
	return Z_ERROR_OK;
}

//????��?��????��?????
 int UDK_API Z_ClearLogData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_ATTLOG;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 2000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//????��?��????��?????
 int UDK_API Z_ClearOpLogData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_OPLOG;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 2000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_RefreshData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_REFRESHDATA;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_FPTempLength(char *TmpData, int *Size)
{
	*Size=BiokeyTemplateLength((UDK_U8*)TmpData);
	if((*Size)>0) return Z_ERROR_OK; else return Z_ERROR_PARAM;
}

 int UDK_API Z_SetFPTempLength(char *TmpData, int Size)
{
	Size=SetBiokeyTemplateLen((UDK_U8*)TmpData,Size);
	if((Size)>0) return Z_ERROR_OK; else return Z_ERROR_PARAM;
}
/*-------------------------------------------
?????��???
---------------------------------------------*/
 int UDK_API Z_RefreshOptions(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_REFRESHOPTION;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetFirmwareVersion(UDK_HANDLE Handle, char *Version)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_GET_VERSION;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, Version, 50, 0, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_OK)
		return Z_ERROR_OK;
	return Z_ERROR_IO;
}

int DecodeValue(char *ret, char *ln)
{
	int	i, l=0;
	for(i=0;i<(int)strlen(ret);i+=2)
		ln[l++]=Hex2Char(ret+i)*16+Hex2Char(ret+i+1);
	ln[l]=0;
	for(i=1;i<l;i++)
		ln[i-1]=ln[i-1]^ln[i];
	ln[l-1]=0;
	return 1;
}

 int UDK_API Z_GetSerialNumber(UDK_HANDLE Handle, char *sn)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "~SerialNumber");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(sn, "0");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(sn, Option+14);
	return Z_ERROR_OK;
}

 int UDK_API Z_GetProductName(UDK_HANDLE Handle, char *ProName)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "~DeviceName");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(ProName, "BioClock I");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(ProName, Option+12);
	return Z_ERROR_OK;
}

 int UDK_API Z_GetVendor(UDK_HANDLE Handle, char *Vendor)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "~OEMVendor");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(Vendor, "ZKSoftware Inc.");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(Vendor, Option+11);
	return Z_ERROR_OK;
}

 int UDK_API Z_GetSensorSN(UDK_HANDLE Handle, char *SensorSN)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "GUID");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(SensorSN, "");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(SensorSN, Option+5);
	return Z_ERROR_OK;
}

 int UDK_API Z_GetSDKVersion(char *Version)
{
	strcpy(Version, "6.2.5.12");
	return Z_ERROR_OK;
}

//?��???????
 int UDK_API Z_GetLanguage(UDK_HANDLE Handle, int *LanguageID)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "Language");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	*LanguageID=atoi(Option+9);
	return Z_ERROR_OK;
}

 int UDK_API Z_SetLanguage(UDK_HANDLE Handle, int LanguageID)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "Language=%d",LanguageID);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?��???
 int UDK_API Z_SetTime(UDK_HANDLE Handle, int Year, int Month, int Day, 
										 int Hour, int Minute, int Second)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_SET_TIME;
	struct tm tmt;
	UDK_U32 t;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	tmt.tm_hour=Hour;
	tmt.tm_mday=Day;
	tmt.tm_min=Minute;
	tmt.tm_mon=Month;  //tm_mon of struct tm is from 0 to 11
	tmt.tm_sec=Second;
	tmt.tm_year=Year;
	t=EncodeTime(&tmt);
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&t, sizeof(t), sizeof(t), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetTime(UDK_HANDLE Handle, int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_GET_TIME;
	struct tm tmt;
	int t;
	if(NULL==h)	return Z_ERROR_NOT_INIT; 
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&t, sizeof(t), 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	DecodeTime(t, &tmt);
	*Hour	=tmt.tm_hour;
	*Day	=tmt.tm_mday;
	*Minute	=tmt.tm_min ;
	*Month	=tmt.tm_mon ;
	*Second	=tmt.tm_sec ;
	*Year	=tmt.tm_year;
	return Z_ERROR_OK;
}

//?��IP???
 int UDK_API Z_GetIPAddress(UDK_HANDLE Handle, char *IPAddress)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "IPAddress");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(IPAddress,Option+10);
	return Z_ERROR_OK;
}

 int UDK_API Z_SetIPAddress(UDK_HANDLE Handle, char *IPAddress)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "IPAddress=%s", IPAddress);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?��??????????
 int UDK_API Z_GetDevicePort(UDK_HANDLE Handle, unsigned short *PortNumber)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "UDPPort");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	*PortNumber=atoi(Option+8);
	return Z_ERROR_OK;
}

 int UDK_API Z_SetDevicePort(UDK_HANDLE Handle, unsigned short PortNumber)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "UDPPort=%d", PortNumber);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 0, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//RS485???��????
 int UDK_API Z_GetDeviceNumber(UDK_HANDLE Handle, unsigned short *DeviceNumber)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "DeviceID");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	*DeviceNumber=atoi(Option+9);
	return Z_ERROR_OK;
}

 int UDK_API Z_SetDeviceNumber(UDK_HANDLE Handle, unsigned short DeviceNumber)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "DeviceID=%d", DeviceNumber);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 0, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}


 int UDK_API Z_GetDeviceStatus(UDK_HANDLE Handle, int StatusItem, int *Value)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_GET_FREE_SIZES;
	int sizes[50];
	//int indexs[]={12,4,6,13,10,8,14,15,16,17,18,19,0,1,2,3,5,7,9,11};
	int indexs[]={12,4,6,13,10,8,14,15,16,17,18,19,0,1,2,3,5,7,9,11,20,22};//21,22?��????????
	//if(StatusItem<=0 || StatusItem>20) return Z_ERROR_PARAM;
	if(StatusItem<=0 || StatusItem>25) return Z_ERROR_PARAM;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->libusb_flag)
	{
		sizes[0] = indexs[StatusItem - 1];
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)sizes, sizeof(sizes), 4, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) 
			return Z_ERROR_IO;
		*Value=sizes[0];
	}
	else
	{
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)sizes, sizeof(sizes), 0, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) 
			return Z_ERROR_IO;
		*Value=sizes[indexs[StatusItem-1]];
	}
	h->dcInit=1;
	h->dcLog=sizes[8];
	h->dcTmp=sizes[6];
	h->dcUser=sizes[4];
	return Z_ERROR_OK;
}


int CalcThreshold(int NewT)
{
	if(NewT<10) return NewT<0?0:NewT*3;
	else return NewT>50? 70: NewT+20;
}

int CalcNewThreshold(int Thr)
{
	if(Thr<30) return Thr<0?0:Thr/3;
	else return Thr>70? 50: Thr-20;
}

#define OptionCount	34+34 //henry 2006-12-29 modify it to 34

static const char *OptionStrs[OptionCount]={
	"DeviceID",
	"NewLng",
	"IdleMinute",
	"LockOn",
	"AlarmAttLog",
	"AlarmOpLog",
	"AlarmReRec",
	"RS232BaudRate",
	"RS232CRC",
	"RS232Stop",
	"",
	"NetworkOn",	//???�H??
	"RS232On",		//RS232????
	"RS485On",		//RS485????
	"VoiceOn",
	"MSpeed",
	"IdlePower",	//
	"AutoPowerOff", //
	"AutoPowerOn",	//20
	"AutoPowerSuspend",
	"AutoAlarm1",
	"MThreshold",	//23
	"EThreshold",
	"VThreshold",
	"ShowScore",
	"UnlockPerson",
	"OnlyPINCard",
	"HiSpeedNet",
	"MustEnroll",	//30
	"TOState",
	"TOPin",	
	"TOMenu",
	"DtFmt",
	"Must1To1",
	"AutoAlarm2",
	"AutoAlarm3",
	"AutoAlarm4",
	"AutoAlarm5",
	"AutoAlarm6",	//40
	"AS1",
	"AS2",
	"AS3",
	"AS4",
	"AS5",
	"AS6",
	"AS7",
	"AS8",
	"AS9",
	"AS10",
	"AS11",
	"AS12",
	"AS13",
	"AS14",
	"AS15",
	"AS16",
	"WGFailedID",
	"WGDuressID",
	"WGSiteCode",
	"WGPulseWidth",	//60
	"WGPulseInterval",
	"~RFSStart",
	"~RFSLen",
	"~RFFPC",
	"CardKey",
	//henry add
	"~ShowState",
	"ControlOn",
	"ControlStartTime",
	"ControlMinute"
};

 int UDK_API Z_GetDeviceInfo(UDK_HANDLE Handle, int InfoItem, int *Value)
{
	PEmHandle h = (PEmHandle )Handle;
    long lv;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100], *v;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	switch(InfoItem)
	{
	case I_AdminCount:
		*Value=500; return Z_ERROR_OK;
	case I_CRC:
		*Value=0; return Z_ERROR_OK;
	case I_STOPBIT:
		*Value=0; return Z_ERROR_OK;
	case I_DATESP:
		*Value=1; return Z_ERROR_OK;
	case I_Option:
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)Value, 100, strlen((char*)Value)+1, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		return Z_ERROR_OK;
	case -1:
            lv = (long)udk_dlopen("zkemsdk.dll",0);
            *Value=(int)lv;
            return Z_ERROR_PARAM;
	case -2:
            lv=(long)udk_dlopen("commpro.dll",0);
            *Value=(int)lv;
            return Z_ERROR_PARAM;
	case -3:
            lv = (long)Handle;
            *Value=(int)lv;
		return Z_ERROR_PARAM;
	case -4:
            lv = (long)h->emh;
            *Value=(int)lv;
		return Z_ERROR_PARAM;
	case -5:
		return Z_ReadData(Handle, (char*)Value, Value[1]);
	case -6:
		{
			cmd=CMD_CLEAR_DATA;
			ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)Value, 4, 1, 3000+h->WaitTimeForACommand);
			if(cmd!=CMD_ACK_OK) return Z_ERROR_IO; else return Z_ERROR_OK;
		}
	default:
		if(InfoItem<1 && InfoItem>OptionCount) return Z_ERROR_PARAM;
		if(InfoItem==65)	return Z_ERROR_PARAM;	//???????��???????
		strcpy(Option, OptionStrs[InfoItem-2]);
		ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		v=Option+strlen(OptionStrs[InfoItem-2])+1;
		if(InfoItem==I_Language)
		{
			*Value=atoi(v);
			if(*Value=='E') *Value=IL_English; else if(*Value=='T') *Value=IL_TChinese; else if(*Value=='L') *Value=IL_Tai; else *Value=IL_Chinese;
		}
		else if(InfoItem==I_BaudRate)
		{
			switch(atoi(v))
			{
			case 1200: *Value=IB_1200; break;
			case 2400: *Value=IB_2400; break;
			case 4800: *Value=IB_4800; break;
			case 9600: *Value=IB_9600; break;
			case 19200: *Value=IB_19200; break;
			case 38400: *Value=IB_38400; break;
			case 57600: *Value=IB_57600; break;
			default: *Value=IB_115200; break;
			}
		}
		else if(InfoItem>=I_MThreshold && InfoItem<=I_VThreshold)
		{
			if(strcmp(h->version,VER504)<0)
				*Value=atoi(v)-20;
			else
				*Value=CalcNewThreshold(atoi(v));
		}
		else
			*Value=atoi(v);
		return Z_ERROR_OK;
	}	
	return Z_ERROR_PARAM;
}

#define OptionExCount	1

const char *OptionExStrs[OptionExCount]={
	"~ProductTime"
};

 int UDK_API Z_GetDeviceStrInfo(UDK_HANDLE Handle, int InfoItem, char *Value)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	/*switch(InfoItem)
	{
	default:*/
	if(InfoItem<1 && InfoItem>OptionExCount) return Z_ERROR_PARAM;
	strcpy(Option, OptionExStrs[InfoItem-1]);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(Value, Option+strlen(OptionExStrs[InfoItem-1])+1);
	return Z_ERROR_OK;
	//}	
	//return Z_ERROR_PARAM;
}

UDK_U32 GetUS(void)
{
	return udk_get_ticks()*1000+(int)(rand()*1000);
}

 int UDK_API Z_SetDeviceInfo(UDK_HANDLE Handle, int InfoItem, int Value)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100],*v;
	int i,r;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	r=InfoItem>=10000;
	InfoItem=InfoItem%10000;
	switch(InfoItem)
	{
	case I_AdminCount:
		return Z_ERROR_OK;
	case I_CRC:
		if(Value==IC_NONE) return Z_ERROR_OK; else return Z_ERROR_UNSUPPORT;
	case I_STOPBIT:
		if(Value==IS_1) return Z_ERROR_OK; else return Z_ERROR_UNSUPPORT;
	case I_DATESP:
		if(Value==ID_MINUS) return Z_ERROR_OK; else return Z_ERROR_UNSUPPORT;
	case I_Option:
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)Value, 0, strlen((char*)Value)+1, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		return Z_ERROR_OK;
	default:
		if(InfoItem<1 && InfoItem>20) return Z_ERROR_PARAM;
		sprintf(Option,"%s", OptionStrs[InfoItem-2]);
		if((Option[0]=='~') && (h->DeviceType==0))
		{
			char ln[40];
			char v[100];
			int len=0;
			char value[20];
			sprintf(value,"%d",Value);
			len=strlen(value);
			ln[0]=GetUS() & 0xFF;
			for(i=0;i<len;i++)
				ln[i+1]=ln[i]^(value[i]);
			for(i=0;i<len+1;i++)
				sprintf(v+i*2,"%02X",ln[i]);
			len=len*2+2;
			i=strlen(Option);
			sprintf(Option+i,"%s","=");
			len=i+2+len;
			sprintf(Option+i+1, "%s", v);
		}else
			sprintf(Option, "%s=%d", OptionStrs[InfoItem-2], Value);
		v=Option+strlen(OptionStrs[InfoItem-2])+1;
		if(InfoItem==I_Language)
		{
			sprintf(v,"%d",Value==IL_English?'E':Value==IL_TChinese?'T':Value==IL_Tai?'L':'S');
		}
		else if(InfoItem==I_BaudRate)
		{
			switch(Value)
			{
			case IB_1200: i=1200; break;
			case IB_2400: i=2400; break;
			case IB_4800: i=4800; break;
			case IB_9600: i=9600; break;
			case IB_19200: i=19200; break;
			case IB_38400: i=38400; break;
			case IB_57600:	i=57600; break;
			default: i=115200;
			}
			sprintf(v, "%d", i);
		}
		else if(InfoItem>=I_MThreshold && InfoItem<=I_VThreshold)
		{
			if(strcmp(h->version,VER504)<0)
				Value+=20;
			else
				Value=CalcThreshold(Value);
			sprintf(v,"%d",Value);
		}
		ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 0, strlen(Option)+1, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		if(r==0)
			if(!(InfoItem==I_BaudRate || InfoItem==I_Language || I_DeviceNumber || 
				InfoItem==I_FunNet || InfoItem==I_FunRS232 || InfoItem==I_FunRS485 || InfoItem==I_Option))
			{
				cmd=CMD_REFRESHOPTION;
				ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
			}
			return Z_ERROR_OK;
	}
	return Z_ERROR_PARAM;
}



/*-------------------------------------------
?��???????
---------------------------------------------*/
//???/??????????��
 int UDK_API Z_EnableDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_ENABLEDEVICE; 
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_DisableDevice(UDK_HANDLE Handle, int TimeOutSec)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_DISABLEDEVICE;
	int TmpTimeOutSec = TimeOutSec;                //zhc add TmpTimeOutSec 2010-06-01, ?????��?TimeOutSec????????????????????????????????????????
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&TmpTimeOutSec, 4, 4, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}

	return Z_ERROR_OK;
}

//??????/???/????/?????��
 int UDK_API Z_RebootDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_RESTART;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	Z_Close(h);
	return Z_ERROR_OK;
}

 int UDK_API Z_PowerOffDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_POWEROFF;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	//Z_Close(h);//ypin
	return Z_ERROR_OK;
}

 int UDK_API Z_SleepDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_SLEEP;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	//Z_Close(h); //yuping
	return Z_ERROR_OK;
}

int UDK_API Z_ReSetDeviceExt(UDK_HANDLE Handle, char *parameters)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_RESTART;
	char szParameter[1024] = {0x0};
	int sendlen = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(NULL != parameters && strlen(parameters) > 0)
	{
		char *p = strstr(parameters, "module=");
		if(NULL == p)
			return Z_ERROR_PARAM;
		strcpy(szParameter, parameters);
		sendlen = strlen(szParameter) + 1;
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, szParameter, 0, sendlen, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	Z_Close(h);
	return Z_ERROR_OK;
}

 
/*
 int UDK_API Z_ResumeDevice(UDK_HANDLE Handle)
{
PEmHandle h = (PEmHandle )Handle;
if(NULL==h)	return Z_ERROR_NOT_INIT;
return Z_ERROR_UNSUPPORT;
}*/

//******************************* add by yuping *************************************
 int UDK_API Z_ResumeDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_RESUME;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SuspendDevice(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_SUSPEND;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//*******************************  add end ***********************************

//??????��??????????
 int UDK_API Z_AutoPowerOff(UDK_HANDLE Handle, int Minutes)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	return Z_ERROR_UNSUPPORT;
}

//?????????????
 int UDK_API Z_PowerOffTime(UDK_HANDLE Handle, int Year, int Month, int Day, int Hour, int Minute)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	return Z_ERROR_UNSUPPORT;
}

 int UDK_API Z_FPTempConvert(char *TmpData1, char *TmpData2, int *Size)
{
	int l=TestTemplate((UDK_U8*)TmpData1, (UDK_U8*)TmpData2);
	if(l>50)
	{
		*Size=l;
		return Z_ERROR_OK;
	}
	else
		return Z_ERROR_PARAM;
}

 int UDK_API Z_FPTempConvertNew(char *TmpData1, char *TmpData2, int *Size)
{
	int l=TestTemplate41((UDK_U8*)TmpData1, (UDK_U8*)TmpData2);
	if(l>50)
	{
		if(*Size>100 && *Size<2048)
		{
			if(*Size<l)
			{
				l=SetBiokeyTemplateLen((UDK_U8*)TmpData2, *Size);
			}
		}
		*Size=l;
		return Z_ERROR_OK;
	}
	else
		return Z_ERROR_PARAM;
}

/*-----------------------------------------------
????????????
-------------------------------------------------*/

 int UDK_API Z_GetUserGroup(UDK_HANDLE Handle, int UserID, int *UserGrp)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERGRP_RRQ;
	char strPin[30] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->IsTFTMachine)
	{
		sprintf(strPin, "%d", UserID);
		*UserGrp = SSR_GetPIN1(Handle, strPin);
	}
	else
	{
		*UserGrp=GetPIN1(h,UserID);
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)UserGrp, 4, 4, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	*UserGrp=*UserGrp & (int)0xff;
	return Z_ERROR_OK;

}

 int UDK_API Z_SetUserGroup(UDK_HANDLE Handle, int UserID, int UserGrp)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERGRP_WRQ;
	int buf[2], pin;
	char strPin[30] = {0};

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (h->IsTFTMachine)
	{
		sprintf(strPin, "%d", UserID);
		pin = SSR_GetPIN1(Handle, strPin);
		buf[0]=pin;
		buf[1]=UserGrp;
	}
	else
	{
		buf[0]=GetPIN1(h,UserID);
		buf[1]=UserGrp;
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)buf, 8, 5, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

typedef struct _TZ_{
	unsigned char intervals[7][2][2];
}TTimeZone, *PTimeZone;

typedef struct _THoliday_{
	unsigned char intervals[24][2][2];
}THoliday, *PHoliday;

 int UDK_API Z_GetTZInfo(UDK_HANDLE Handle, int TZIndex, char *TZ)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[100];
	unsigned short cmd=CMD_TZ_RRQ;
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(int*)buf=TZIndex;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 100, 4, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	/*yuping del, ???? ????????????bug
	for(i=0;i<7;i++)
	{
	sprintf(TZ,"%02d%02d%02d%02d", ((PTimeZone)buf)->intervals[i][0][0],((PTimeZone)buf)->intervals[i][0][1],
	((PTimeZone)buf)->intervals[i][1][0],((PTimeZone)buf)->intervals[i][1][1]);
	TZ+=8;
	}//*/
	//yuping add
	if(!h ->IsTFTMachine)
	{
		for(i=0;i<7;i++)
		{
			sprintf(TZ,"%02d%02d%02d%02d", ((PTimeZone)buf)->intervals[i][0][0],((PTimeZone)buf)->intervals[i][0][1],
				((PTimeZone)buf)->intervals[i][1][0],((PTimeZone)buf)->intervals[i][1][1]);
			TZ+=8;
		}
	}
	else
	{
		char *DataBuf = buf + sizeof(short);//????2???????TZIndex
		for(i=0;i<7;i++)
		{
			sprintf(TZ,"%02d%02d%02d%02d", ((PTimeZone)DataBuf)->intervals[i][0][0],((PTimeZone)DataBuf)->intervals[i][0][1],
				((PTimeZone)DataBuf)->intervals[i][1][0],((PTimeZone)DataBuf)->intervals[i][1][1]);
			TZ+=8;
		}
	}
	//end
	return Z_ERROR_OK;
}

 int UDK_API Z_SetTZInfo(UDK_HANDLE Handle, int TZIndex, char *TZ)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[100];
	unsigned short cmd=CMD_TZ_WRQ;
	int i;
	PTimeZone tz=(PTimeZone)(buf+4);
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(int*)buf=TZIndex;
	for(i=0;i<7;i++)
	{
		tz->intervals[i][0][0]=(TZ[0]-'0')*10+(TZ[1]-'0');
		if(tz->intervals[i][0][0]<0 || tz->intervals[i][0][0]>=24) return Z_ERROR_PARAM;
		tz->intervals[i][0][1]=(TZ[2]-'0')*10+(TZ[3]-'0');
		if(tz->intervals[i][0][1]<0 || tz->intervals[i][0][1]>=60) return Z_ERROR_PARAM;
		tz->intervals[i][1][0]=(TZ[4]-'0')*10+(TZ[5]-'0');
		if(tz->intervals[i][1][0]<0 || tz->intervals[i][1][0]>=24) return Z_ERROR_PARAM;
		tz->intervals[i][1][1]=(TZ[6]-'0')*10+(TZ[7]-'0');
		if(tz->intervals[i][1][1]<0 || tz->intervals[i][1][1]>=60) return Z_ERROR_PARAM;
		TZ+=8;
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 4+sizeof(TTimeZone), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetUnlockGroups(UDK_HANDLE Handle, char *Grps)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_ULG_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*Grps=0;
	ZEMBPRO_SENDCMD(h->emh, &cmd, Grps, 200, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SetUnlockGroups(UDK_HANDLE Handle, char *Grps)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_ULG_WRQ;
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;	
	i=strlen(Grps);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Grps, i, i, h->WaitTimeForACommand);	
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

int GetTZs(PEmHandle h, WORD *cmd, int ID, int*TZs, int *UserGrp)
{
	char buf[100]={0};
	int iID = 0;
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	*(int*)buf = ID;
	ZEMBPRO_SENDCMD(h->emh, cmd, buf, 100, 4, h->WaitTimeForACommand);
	if(*cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}	

	if (h->IsTFTMachine)
	{
		// ???????????2010-07-14
		/*TZs[0] = ((UDK_U16*)buf)[0];
		TZs[1] = ((UDK_U16*)buf)[1];
		TZs[2] = ((UDK_U16*)buf)[2];
		TZs[3] = ((UDK_U16*)buf)[3];
		*UserGrp = TZs[0];*/

		TZs[0] = ((UDK_U16*)buf)[1];
		TZs[1] = ((UDK_U16*)buf)[2];
		TZs[2] = ((UDK_U16*)buf)[3];
		TZs[3] = ((UDK_U16*)buf)[0];
		*UserGrp = (TZs[3] == 1) ? 0:1; // TZs[3]?1?????????????
	}
	else
	{
		iID = (*(int*)buf);////ID = (*(int*)buf);
		memset(TZs, 0, 3*4);
		if(iID<0)
		{
			iID = -1-iID;//ID=-1-ID;
			if(UserGrp) *UserGrp=1;
		}
		else
		{
			if(UserGrp)
				*UserGrp=0;
		}
		if(iID>3)
			iID = 3;//if(ID>3) ID=3;		
		memcpy(TZs, buf+4, iID*4);//memcpy(TZs, buf+4, ID*4);
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_GetGroupTZs(UDK_HANDLE Handle, int GroupIndex, int *TZs)
{
	PEmHandle h = (PEmHandle)Handle;
	unsigned short cmd=CMD_GRPTZ_RRQ;
	TZs[0]=0;TZs[1]=0;TZs[2]=0;
	return GetTZs(h, &cmd, GroupIndex, TZs, NULL);
}

int SetTZs(PEmHandle h, WORD *cmd, int ID, int*TZs)
{
	char buf[100] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(int*)buf=ID;
	if(TZs)
	{
		((int*)buf)[1]=3;
		if (h->IsTFTMachine)
		{
			((int*)buf)[1]=TZs[3];//????????????
		}
		else
		{
			if(TZs[0]==0)
			{	
				((int*)buf)[1]=0;//???????????
			}
			else if(TZs[1]==0)
			{
				((int*)buf)[1]=1;//????????1
			}
			else if(TZs[2]==0)
			{
				((int*)buf)[1]=2;//????????1??????????2
			}
		}
		((int*)buf)[2]=TZs[0];
		((int*)buf)[3]=TZs[1];
		((int*)buf)[4]=TZs[2];
		ZEMBPRO_SENDCMD(h->emh, cmd, buf, 100, 4*5, h->WaitTimeForACommand);
	}
	else
	{
		ZEMBPRO_SENDCMD(h->emh, cmd, buf, 100, 4, h->WaitTimeForACommand);
	}
	if(*cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SetGroupTZs(UDK_HANDLE Handle, int GroupIndex, int *TZs)
{
	unsigned short cmd=CMD_GRPTZ_WRQ;
	return SetTZs((PEmHandle )Handle, &cmd, GroupIndex, TZs);
}

 int UDK_API Z_GetUserTZs(UDK_HANDLE Handle, int UserID, int *TZs, int *GroupFlag)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTZ_RRQ;
	int ret, UserGrp=0, ReadUserGrp=*TZs, pin = UserID;
	char strPin[30] = {0};
	if (h->IsTFTMachine)
	{
		sprintf(strPin, "%d", UserID);
		pin = SSR_GetPIN1(Handle, strPin);
	}
	else
	{
		pin=GetPIN1(Handle,UserID);
	}
	ret=GetTZs(h, &cmd, pin, TZs, &UserGrp);
	*GroupFlag = UserGrp;
	if(ReadUserGrp==-1 && UserGrp)//?
	{
		TZs[2]=TZs[0];
		TZs[0]=-1;
	}
	return ret;
}

 int UDK_API Z_SetUserTZs(UDK_HANDLE Handle, int UserID, int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTZ_WRQ;	
	//dsl 2007.10.10
	char strPin[30] = {0};	
	int pin;

	if (h->IsTFTMachine)
	{
		sprintf(strPin, "%d", UserID);
		pin = SSR_GetPIN1(Handle, strPin);
		return SetTZs(h, &cmd, pin, TZs);
	}
	else
	{
		return SetTZs(h, &cmd, GetPIN1(Handle,UserID), TZs);
	}
}

 int UDK_API Z_Unlock(UDK_HANDLE Handle, int Delay)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_UNLOCK;
	int TmpDelay = Delay; //zhc add TmpDelay 2010-06-01, ?????��?Delay????????????????????????????????????????

	if(NULL==h)	
	{
		return Z_ERROR_NOT_INIT;
	}

	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&TmpDelay, 0, 4, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK) 
	{
		return Z_ERROR_IO;
	}

	return Z_ERROR_OK;
}

 int UDK_API Z_GetACFun(UDK_HANDLE Handle, int *ACFun)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char *v, Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "~LockFunOn");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	v=Option+strlen("~LockFunOn")+1;
	*ACFun=atoi(v);
	return Z_ERROR_OK;
}

/* int UDK_API Z_GetSMS(UDK_HANDLE Handle, int Index, int *UserID, char *SMS)
{
PEmHandle h = (PEmHandle )Handle;
unsigned short cmd=CMD_OPTIONS_RRQ;
char Option[100];
int l;
if(NULL==h)	return Z_ERROR_NOT_INIT;
sprintf(Option, "SMS%d", Index);
l=strlen(Option);
ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, l+1, h->WaitTimeForACommand);
if(cmd==CMD_ACK_ERROR)
{
SMS[0]=0;
*UserID=0;
return Z_ERROR_NO_DATA;
}
if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
if(strlen(Option)<l+1+5)
{
SMS[0]=0;
*UserID=0;
return Z_ERROR_NO_DATA;
}
strcpy(SMS, Option+1+l+5);
*UserID=(Hex2Char(Option+l+1)<<12)+(Hex2Char(Option+l+2)<<8)+(Hex2Char(Option+l+3)<<4)+Hex2Char(Option+l+4);
return Z_ERROR_OK;
}

 int UDK_API Z_SetSMS(UDK_HANDLE Handle, int Index, int UserID, char *SMS)
{
PEmHandle h = (PEmHandle )Handle;
unsigned short cmd=CMD_OPTIONS_WRQ;
char Option[100];
int l;
if(NULL==h)	return Z_ERROR_NOT_INIT;
if(Index>100) return Z_ERROR_PARAM;
if(strlen(SMS)>64) SMS[64]=0;
if((SMS==0) || (0==*SMS))
{
sprintf(Option, "SMS%d=", Index);
}
else
sprintf(Option, "SMS%d=%04X&%s", Index, GetPIN1(h, UserID), SMS);
l=strlen(Option);
ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, l+1, h->WaitTimeForACommand);
if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
return Z_ERROR_OK;
}
*/
 int UDK_API Z_GetSMS(UDK_HANDLE Handle, int ID, int *Tag, int *ValidMinutes, int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second, char* Content)
{
	PEmHandle h = (PEmHandle )Handle;
	TTime t;
	unsigned short cmd = CMD_SMS_RRQ;

	if (h->NewSmsFormat)
	{
		PSmsNew sms;
		char smsbuffer[sizeof(TSmsNew)+2];	
		if(NULL==h)	return Z_ERROR_NOT_INIT;

		((UDK_U16*)smsbuffer)[0]=ID;
		ZEMBPRO_SENDCMD(h->emh, &cmd, smsbuffer, sizeof(TSmsNew)+2, 2, h->WaitTimeForACommand);

		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;

		sms=(PSmsNew)smsbuffer;	
		*Tag = sms->Tag;
		*ValidMinutes = sms->ValidMinutes;
		DecodeTime(sms->StartTime , &t);
		*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
		*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
		memcpy(Content, sms->Content, MAX_SMSNEW_CONTENT_SIZE);
	}
	else
	{
		PSms sms;
		char smsbuffer[sizeof(TSms)+2];	
		if(NULL==h)	return Z_ERROR_NOT_INIT;
		//memset((void*)&sms,0,sizeof(TSms));
		((UDK_U16*)smsbuffer)[0]=ID;
		ZEMBPRO_SENDCMD(h->emh, &cmd, smsbuffer, sizeof(TSms)+2, 2, h->WaitTimeForACommand);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		sms=(PSms)smsbuffer;	
		*Tag = sms->Tag;
		*ValidMinutes = sms->ValidMinutes;
		DecodeTime(sms->StartTime , &t);
		*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
		*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
		memcpy(Content, sms->Content, MAX_SMS_CONTENT_SIZE);	
	}
	return Z_ERROR_OK;
}
 int UDK_API Z_SetSMS(UDK_HANDLE Handle, int ID, int Tag, int ValidMinutes, int Year, int Month, int Day, int Hour, int Minute, int Second, char* Content)
{
	PEmHandle h = (PEmHandle )Handle;  	
	unsigned short cmd = CMD_SMS_WRQ;
	struct tm tmt;
	UDK_U32 t;

	if(NULL==h)	return Z_ERROR_NOT_INIT;

	tmt.tm_hour=Hour;
	tmt.tm_mday=Day;
	tmt.tm_min=Minute;
	tmt.tm_mon=Month;  //tm_mon of struct tm is from 0 to 11
	tmt.tm_sec=Second;
	tmt.tm_year=Year;
	t=EncodeTime(&tmt);

	if (h->NewSmsFormat)
	{
		TSmsNew sms;
		memset((void*)&sms,0,sizeof(TSmsNew));	
		sms.ID = (UDK_U16)ID;
		sms.Tag = (UDK_U8)Tag;  
		sms.ValidMinutes = (UDK_U16)ValidMinutes;
		sms.StartTime = t;
		memcpy(sms.Content,Content, MAX_SMSNEW_CONTENT_SIZE);

		//ZEMBPRO_SENDCMD(h->emh, &cmd, &sms, sizeof(TSmsNew), sizeof(TSmsNew), h->WaitTimeForACommand);
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&sms, sizeof(TSmsNew), sizeof(TSmsNew), h->WaitTimeForACommand);
	}
	else
	{
		TSms sms;
		memset((void*)&sms,0,sizeof(TSms));	
		sms.ID = (UDK_U16)ID;
		sms.Tag = (UDK_U8)Tag;  
		sms.ValidMinutes = (UDK_U16)ValidMinutes;
		sms.StartTime = t;
		memcpy(sms.Content,Content, MAX_SMS_CONTENT_SIZE);

		//ZEMBPRO_SENDCMD(h->emh, &cmd, &sms, sizeof(TSms), sizeof(TSms), h->WaitTimeForACommand);	
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&sms, sizeof(TSms), sizeof(TSms), h->WaitTimeForACommand);	
	}

	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
 int UDK_API Z_DeleteSMS(UDK_HANDLE Handle, int ID)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_DELETE_SMS;
	UDK_U16 buf = 0;
	int i = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf=ID;
	//i=ZEMBPRO_SENDCMD(h->emh, &cmd, &buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SetUData(UDK_HANDLE Handle, int PIN,int PIN2,int SmsID)
{
	PEmHandle h = (PEmHandle )Handle;
	TUData ud;
	int pin;
	unsigned short cmd=CMD_UDATA_WRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset((void*)&ud,0,sizeof(TUData));
	if(PIN!=0)
		ud.PIN=PIN;
	else
	{
		pin=Z_QueryUserByPIN2(Handle,PIN2);
		if(pin==0) 
			return Z_ERROR_NO_DATA;
		else
			ud.PIN =  pin;
	}
	ud.SMSID=SmsID;
	//ZEMBPRO_SENDCMD(h->emh, &cmd, &ud, sizeof(TUData), sizeof(TUData), h->WaitTimeForACommand);
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&ud, sizeof(TUData), sizeof(TUData), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_DeleteUData(UDK_HANDLE Handle, int PIN,int PIN2, int SmsID)
{
	PEmHandle h = (PEmHandle )Handle;
	TUData ud;
	int i = 0,pin = 0;
	unsigned short cmd=CMD_DELETE_UDATA;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset((void*)&ud,0,sizeof(TUData));
	if(PIN!=0)
		ud.PIN=PIN;
	else
	{
		pin=Z_QueryUserByPIN2(Handle,PIN2);
		if(pin==0) 
			return Z_ERROR_NO_DATA;
		else
			ud.PIN =  pin;
	}
	ud.SMSID=SmsID;
	//i=ZEMBPRO_SENDCMD(h->emh, &cmd, &ud, 0,sizeof(TUData),  4000+h->WaitTimeForACommand);
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&ud, 0,sizeof(TUData),  4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
} 
/*
 int UDK_API Z_AppendSMS(UDK_HANDLE Handle, int UserID, int GroupIndex, char *SMS, int Year, int Month, int Day, int Hour, int Minute, int Second, int ValidMinutes)
{
TTime t;
int PIN;
t.tm_hour = Hour;
t.tm_min = Minute;
t.tm_sec = Second;
t.tm_mday= Day;
t.tm_mon = Month; 
t.tm_year= Year;
if(UserID==0)
PIN=GroupIndex;
else
PIN=GetPIN1(Handle, UserID);
return Z_AppendUData(Handle, UserID==0?UDATA_TAG_GROUPSMS:UDATA_TAG_USERSMS, PIN, ValidMinutes, EncodeTime(&t), SMS, strlen(SMS)+1);
}
*/

//???????????????9��????????????????????????????????????????zhc 2010-04-22??
 int UDK_API Z_StartEnroll(UDK_HANDLE Handle, int UserID, int FingerID)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_STARTENROLL;
	char Buffer[30] = {0};
	int res, sendlen = 0;

	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if(h->PINWidth <= 5)
	{
		*(WORD*)Buffer = UserID;
		Buffer[2] = FingerID;
		sendlen = 2 + 1;
	}
	else
	{
		*(int*)Buffer = UserID;
		Buffer[4] = FingerID;
		sendlen = 4 + 1;

		//9��??????????1,?????????��?????????????????????pin2?pin???????????��??????????????2010.09.16
		gIsEnroll = 1;
	}

	res=ZEMBPRO_SENDCMD(h->emh, &cmd, Buffer, 10, sendlen, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		return res;
	}

	return Z_ERROR_OK;
}

 int UDK_API Z_StartVerify(UDK_HANDLE Handle, int UserID, int FingerID)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_STARTVERIFY;
	char Buffer[100];
	int res;
	*(WORD*)Buffer=GetPIN1(h,UserID);
	Buffer[2]=FingerID;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	res=ZEMBPRO_SENDCMD(h->emh, &cmd, Buffer, 100, 3, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return res;
	return Z_ERROR_OK;
}

 int UDK_API Z_StartIdentify(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_STARTVERIFY;
	int res;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	res=ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return res;
	return Z_ERROR_OK;
}

 int UDK_API Z_CancelOperation(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CANCELCAPTURE;
	int res;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	res=ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return res;
	return Z_ERROR_OK;
}

 int UDK_API Z_QueryState(UDK_HANDLE Handle, int *State)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_STATE_RRQ;
	char Buffer[100];
	int replayID;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	replayID=ZEMBPRO_SENDCMD(h->emh, &cmd, Buffer, 100, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	//*State=*Buffer;
	*State=replayID;
	return Z_ERROR_OK;
}


static unsigned short in_chksum(unsigned char *p, int len)
{
	unsigned long sum=0;

	while(len > 1) {
		sum += *((unsigned short*)p); p+=2;
		if( sum & 0x80000000 ) 
			sum = (sum & 0xFFFF) + (sum >> 16);
		len -= 2;
	}

	if(len) 
		sum += (unsigned short) *(unsigned char*) p;

	while(sum >> 16) 
		sum = (sum & 0xFFFF) + (sum >> 16);

	return (unsigned short)~sum;
}

char *LoadFirmware(UDK_HANDLE Handle,char *FirmwareFile, char *Version, int *Length)
{


	PEmHandle h = (PEmHandle )Handle; 
	FILE *fh;
	FILE *fp = NULL;
	char line[4000], linename[20],strTemp[100];
	int i=0, dataline=0, checksum=0, position=0;
	char *fdata=NULL;

	//char strbuf[4000] = {0};	
	//fp = fopen("d:\\rsagentlog11.txt","a+");	

	fh=fopen(FirmwareFile, "r");
	//if(fp) {
	//	memset(strbuf, 0, sizeof(strbuf));
	//	sprintf(strbuf, "\n 11111111111__%s-%d",__FILE__, __LINE__);
	//	fwrite(strbuf, 1, strlen(strbuf), fp);
	//}
	if(fh!=NULL)
	{
		/*if(fp) {
			memset(strbuf, 0, sizeof(strbuf));
			sprintf(strbuf, "\n fopen ok = %d__%s-%d", fh, __FILE__, __LINE__);
			fwrite(strbuf, 1, strlen(strbuf), fp);
		}*/
		sprintf(linename,"Data%d=",dataline);
		/*if(fp) {
			memset(strbuf, 0, sizeof(strbuf));
			sprintf(strbuf, "\n linename = %s__%s-%d", linename, __FILE__, __LINE__);
			fwrite(strbuf, 1, strlen(strbuf), fp);
		}*/
		while(fgets(line, 4000, fh))
		{
			/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n ddddd i=%d ,linename=%s-------- line = %s__%s-%d",i,linename, line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
			}
			memset(line, 0, sizeof(line));*/
			if((i<=0) && (0==strncmp(line,"FirmwareVersion=", strlen("FirmwareVersion="))))
			{
				/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n FirmwareVersion line = %s__%s-%d", line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/

				strcpy(Version, line+strlen("FirmwareVersion="));
				if(h->DeviceType==1)
				{
					/*if(fp) {
					memset(strbuf, 0, sizeof(strbuf));
					sprintf(strbuf, "\n h->DeviceType==1 line = %s__%s-%d", line, __FILE__, __LINE__);
					fwrite(strbuf, 1, strlen(strbuf), fp);
					}*/
					break;	//????????? Zem200???????Zem100?????????
				}
				strcpy(strTemp,Version);
				ConvertMonth(strTemp);
				if(strcmp(strTemp,h->version)<=0) 
				{
					/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n strcmp(strTemp,h->version)<=0 line = %s__%s-%d", strTemp, h->version, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
					break;
				}
			}
			else if((i<=0) && (0==strncmp(line,"ZEM200_FirmwareVersion=", strlen("ZEM200_FirmwareVersion="))))
			{

				/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n line = %s__%s-%d", line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
				strcpy(Version, line+strlen("ZEM200_FirmwareVersion="));
				if(h->DeviceType==0) break;	//????????? Zem100???????Zem200?????????
				strcpy(strTemp,Version);
				ConvertMonth(strTemp);
				if(strcmp(strTemp,h->version)<=0) break;
			}
			else if(strncmp(line, "FirmwareLength=",strlen("FirmwareLength="))==0)
			{
				/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n FirmwareLength line = %s__%s-%d", line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
				*Length=atoi(line+strlen("FirmwareLength="));
				fdata=(char*)udk_malloc(4000+*Length);
				i++;
			}
			else if(strncmp(line, "FirmwareCheckSum=",strlen("FirmwareCheckSum="))==0)
			{
				/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n FirmwareCheckSum line = %s__%s-%d", line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
				checksum=atoi(line+strlen("FirmwareCheckSum="));
				i++;
			}
			else if(i==2)
			{
				/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n i=2 linename=%s-- line = %s__%s-%d",linename, line, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
				if(strncmp(line, linename, strlen(linename))==0)
				{
					position+=Decode16(line+strlen(linename), fdata+position);
					sprintf(linename,"Data%d=",++dataline);
					/*if(fp) {
					memset(strbuf, 0, sizeof(strbuf));
					sprintf(strbuf, "\n position = %s_*Length=%s_%s-%d", position,*Length, __FILE__, __LINE__);
					fwrite(strbuf, 1, strlen(strbuf), fp);
					}*/
					if(position==*Length) break;
				}
			}
		}
		fclose(fh);
	}
	if(position==*Length)
	{
		/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n position = %s_*Length=%s_%s-%d", position,*Length, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
		if(position) 
			if(in_chksum((unsigned char*)fdata, position)==checksum)
			{				
				//fclose(fp);
				return fdata;
			}
	}
	/*if(fp) {
				memset(strbuf, 0, sizeof(strbuf));
				sprintf(strbuf, "\n faile position = %s_*Length=%s_%s-%d", position,*Length, __FILE__, __LINE__);
				fwrite(strbuf, 1, strlen(strbuf), fp);
				}*/
	if(fdata)
		udk_free(fdata);

	//fclose(fp);
	return NULL;
}

char *LoadFile(char *FileName, char *Header, int *Length)
{
	FILE *fh;
	char line[4000], linename[20],strTemp[100];
	int i=0, dataline=0, checksum, position=0;
	char *fdata=NULL;
	fh=fopen(FileName, "r");
	if(fh!=NULL)
	{
		sprintf(linename,"Data%d=",dataline);
		char* p = fgets(line, 4000, fh);              //???[Options]?????
		while(fgets(line, 4000, fh))
		{
			if(i<=0)                        //FirmwareVersion=
			{
				strcpy(Header, line); 
				strcat(Header, ":");
				i++;
			}
			else if(strncmp(line, "FirmwareLength=",strlen("FirmwareLength="))==0)
			{
				strcat(Header, line);
				strcat(Header, ":");
				*Length=atoi(line+strlen("FirmwareLength=")) + 4000;
				fdata=(char*)udk_malloc(*Length);
				i++;
			}
			else if(strncmp(line, "FirmwareCheckSum=",strlen("FirmwareCheckSum="))==0)
			{
				strcat(Header, line);
				checksum=atoi(line+strlen("FirmwareCheckSum="));
				i++;
			}
			else if(i==3)
			{
				if(strncmp(line, linename, strlen(linename))==0)
				{
					position+=Decode16(line+strlen(linename), fdata+position);
					sprintf(linename,"Data%d=",++dataline);
					if(position==*Length) break;
				}
			}
		}
		fclose(fh);
	}
	return fdata;
}

 int UDK_API Z_UpdateFirmware(UDK_HANDLE Handle, char *FirmwareFile)
{

	char *fdata;
	PEmHandle h = (PEmHandle )Handle; 
	unsigned short cmd=CMD_UPDATE_FIRMWARE;
	int len, CmdBuf[2];
	char version[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	fdata=LoadFirmware(h,FirmwareFile, version, &len);
	if(fdata)
	{
		CmdBuf[0]=UPDATE_CFIRMWARE;
		CmdBuf[1]=0xa0000000;
		ZEMBPRO_SENDCMDDATA(h->emh, &cmd, fdata, len, (char*)CmdBuf, sizeof(CmdBuf), 4*h->WaitTimeForACommand);
		udk_free(fdata);
		if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
		return Z_ERROR_OK;
	}
	return Z_ERROR_PARAM;
}

//#define MAXSIZE 2*1024*1024
#define MAXSIZE 1024*1024*70  //update template for ZKFPV10 10000 tmps
#define STD_SEC_SIZE	64*1024
#define CUSTFILESIZE 1024*1024*3  //dsl 2008.4.16
typedef int (*TExpandItFromFile)(char *datafile, char *data2, int *len2);
typedef int (*TCompressItToFile)(char *data1, char *datafile, int *len1);

 int UDK_API Z_BackupData(UDK_HANDLE Handle, char *DataFile)
{
	char *data;
	int res=Z_ERROR_UNSUPPORT;
	PEmHandle h = (PEmHandle )Handle;
	data=(char*)udk_malloc(MAXSIZE);
	if(data)
	{
		UDK_HANDLE m=udk_dlopen("plce.dll",0);
		if(m)
		{
			TCompressItToFile f=(TCompressItToFile)udk_dlsym(m, "CompressItToFile");
			if(f)
			{
				WORD cmd;
				res=Z_ERROR_IO;
				cmd=CMD_GET_DATA_LAYOUT;
				if(ZEMBPRO_SENDCMD(h->emh, &cmd, data, MAXSIZE, 0, 2000))
				{
					int FreeCount=data[1];
					int FreeStart=data[0];
					int i=0, position=0, size;
					char *Buffer;
					UDK_U8 Context[1000];
					Buffer=(char*)udk_malloc(STD_SEC_SIZE+20);
					memcpy(Context, data+2, FreeCount);
					while(i<FreeCount)
					{
						if((Context[i]!=0xFF) && (Context[i]<10) && (Context[i]!=4/*FCT_OPLOG*/))	//Database sectors
						{
							cmd=CMD_QUERY_FIRMWARE;
							((DWORD*)Buffer)[0]=(DWORD)0xff800000+512*1024+(DWORD)(i*STD_SEC_SIZE);//??????
							((DWORD*)Buffer)[1]=STD_SEC_SIZE;//??��????????
							ZEMBPRO_READDATA(h->emh, &cmd, Buffer, STD_SEC_SIZE+20, 8, h->BlockSize, 2000);
							if(cmd!=CMD_ACK_OK)
								break;
							else  //?????????????
							{
								memcpy(data+position, Buffer, STD_SEC_SIZE);
								position+=STD_SEC_SIZE;								
							}
						}
						else if(Context[i]==4) //FCT_OPLOG ???????
						{
							cmd=CMD_DB_RRQ;
							Buffer[4]=4;
							size=ZEMBPRO_READDATA(h->emh, &cmd, Buffer+4, STD_SEC_SIZE+20, 1, h->BlockSize, 2000);
							if(cmd!=CMD_ACK_OK)
								break;
							else  //?????????????
							{
								memset(data+position, 0xFF, STD_SEC_SIZE);
								Buffer[0]=4; Buffer[1]=0; Buffer[2]=0; Buffer[3]=0;
								memcpy(data+position, Buffer, size);
								position+=STD_SEC_SIZE;
								
							}
						}
						i++;
					}
					if((position==0) && (i==FreeCount))
					{
						res=Z_ERROR_NO_DATA;
					}
					else if(i<FreeCount)
					{
						res=Z_ERROR_IO;
					}
					else if(position)
					{
						if(f(data, DataFile, &position))
						{
							res=Z_ERROR_OK;
						}
						else
							res=Z_ERROR_PARAM;
					}
					udk_free(Buffer);
				}					
			}
			udk_dlclose(m);
		}
		udk_free(data);
	}
	return res;
}

 int UDK_API Z_RestoreData(UDK_HANDLE Handle, char *DataFile)
{
	char *data;
	int res=Z_ERROR_UNSUPPORT;
	PEmHandle h = (PEmHandle )Handle;
	data=(char*)udk_malloc(MAXSIZE);
	if(data)
	{
		UDK_HANDLE m=udk_dlopen("plce.dll",0);
		if(m)
		{
			TExpandItFromFile f=(TExpandItFromFile)udk_dlsym(m, "ExpandItFromFile");
			if(f)
			{
				int len=MAXSIZE;
				len=f(DataFile, data, &len);
				if(len)
				{
					WORD cmd=CMD_DISABLEDEVICE;
					res=Z_ERROR_IO;
					ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
					cmd=CMD_CLEAR_DATA;
					ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
					if(cmd!=CMD_ACK_OK)
						res=Z_ERROR_REPEAT_DATA;
					else
						if(ZEMBPRO_SENDDATA(h->emh, data, len, 2500))
						{
							*((int*)data)=UPDATE_FLASH;
							((int*)data)[1]=512*1024;
							cmd=CMD_UPDATE_FIRMWARE;
							ZEMBPRO_SENDCMD(h->emh, &cmd, data, MAXSIZE, 8, 20000);
							if(cmd==CMD_ACK_OK)
							{
								res=Z_ERROR_OK;
								cmd=CMD_REFRESHDATA;
								ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
							}
						}					
				}
				else
					res=Z_ERROR_PARAM;
			}
			udk_dlclose(m);
		}
		udk_free(data);
	}
	return res;
}
/*yuping del
int MCUCommand(UDK_HANDLE Handle, char cmd, char *Data, int Len)
{
PEmHandle h = (PEmHandle )Handle;
char Buffer[100];
unsigned short fcmd=CMD_MCU_COMMAND;
if(NULL==h)	return Z_ERROR_NOT_INIT;
Buffer[0]=cmd;
Buffer[1]=Len;
Buffer[2]=0;
Buffer[3]=0;
if(Data && Len)
memcpy(Buffer+4, Data, Len);
ZEMBPRO_SENDCMD(h->emh, &fcmd, Buffer, 100, 4+Len, h->WaitTimeForACommand);
if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
return Z_ERROR_OK;
}*/
//add by yuping
int MCUCommand(UDK_HANDLE Handle, char MCUCmd, char *Data, int Len)
{
	PEmHandle h = (PEmHandle )Handle;
	char Buffer[100];
	unsigned short cmd=CMD_MCU_COMMAND;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	Buffer[0]=MCUCmd;
	Buffer[1]=Len;
	Buffer[2]=0;
	Buffer[3]=0;
	if(Data && Len)
		memcpy(Buffer+4, Data, Len);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Buffer, 100, 4+Len, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
//add end

 int UDK_API Z_WriteLCD(UDK_HANDLE Handle, int Row, int Col, char *Text)
{
	char buf[100];
	int len=3;
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_WRITE_LCD;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf[0]=Row;
	buf[1]=Col;
	buf[2]=0;
	len+=strlen(Text)+1;
	if(len>100) len=100;
	strncpy(buf+3, Text, len-3);
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 100, len, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_ClearLCD(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_CLEAR_LCD;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_Beep(UDK_HANDLE Handle, int DelayMS)
{
	char d=DelayMS/20;
	return MCUCommand(Handle, 3, &d, 1);
}

 int UDK_API Z_PlayVoice(UDK_HANDLE Handle, int Position, int Length)
{
	char buf[2];
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_TESTVOICE;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf[0]=Position;
	buf[1]=Length;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 2, 2, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_PlayVoiceByIndex(UDK_HANDLE Handle, int Index)
{
	char buf[2];
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_TESTVOICE;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf[0]=Index;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 2, 1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_EnableClock(UDK_HANDLE Handle, int Enabled)
{
	char buf[2];
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_ENABLE_CLOCK;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf[0]=Enabled;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 2, 1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

int WriteBitmap(UDK_U8 *buffer, int Width, int Height, char *file)
{
	char Buffer[0x500];
	BITMAPFILEHEADER *bmpfheader=(BITMAPFILEHEADER *)Buffer;
	BITMAPINFO *bmpinfo=(BITMAPINFO *)(((char*)bmpfheader)+14);
	int i,w;
	FILE *f;
	memset(bmpfheader,0,0x500);
	bmpfheader->bfType =19778;
	bmpfheader->bfSize = ((Width+3)/4)*4*Height+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD);
	bmpfheader->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD);
	bmpinfo->bmiHeader.biWidth=Width;
	bmpinfo->bmiHeader.biHeight=Height;
	bmpinfo->bmiHeader.biBitCount=8;
	bmpinfo->bmiHeader.biClrUsed=0;
	bmpinfo->bmiHeader.biSize=sizeof(bmpinfo->bmiHeader);
	bmpinfo->bmiHeader.biPlanes=1;
	bmpinfo->bmiHeader.biSizeImage=((Width+3)/4)*4*Height;
	f=fopen(file, "wb");
	if(f)
	{
		for(i=1;i<256;i++)
		{
			bmpinfo->bmiColors[i].rgbBlue=i;
			bmpinfo->bmiColors[i].rgbGreen=i;
			bmpinfo->bmiColors[i].rgbRed=i;
		}
		fwrite(Buffer, sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD), 1, f);

		w = ((Width+3)/4)*4;

		for(i=0; i<Height; i++)
		{
			fwrite(buffer, Width, 1, f);
			if(w-Width)
				fwrite(buffer, w-Width, 1, f);
			buffer+=Width;
		}
		fclose(f);
		return Width*Height;
	}
	return 0;
}

 int UDK_API Z_CaptureImage(UDK_HANDLE Handle, int FullImage, int *Width, int *Height, char *Image, char *ImageFile)
{
	PEmHandle h = (PEmHandle )Handle;
	int PackSize=0, Size;
	WORD cmd = CMD_CAPTUREIMAGE;
	char *Buffer=NULL, *p;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	Buffer=(char*)udk_malloc(640*480+20);
	if(!FullImage)
	{
		cmd=CMD_CAPTUREFINGER;
		PackSize=sizeof(int);
		*(int*)Buffer=500;
	}
	if(*Width)
	{
		*(int*)(Buffer+PackSize)=*Width;
		PackSize+=sizeof(int);
	}
	Size=ZEMBPRO_READDATA(h->emh, &cmd, Buffer, 640*480+20, PackSize, h->BlockSize, h->WaitTimeForACommand*2);
	if(cmd==CMD_ACK_OK)
	{
		if(Size==640*480) 
		{
			*Width = 640;
			*Height = 480;
			p=Buffer;
			Size+=sizeof(int)*3;
		}
		else
		{
			int dpi=*(int*)Buffer;
			*Width=((int*)Buffer)[1];
			*Height=((int*)Buffer)[2];
			p=Buffer+sizeof(int)*3;
		}
		if(Size!=*Height**Width+sizeof(int)*3)
			cmd=CMD_ACK_ERROR;
		else
		{
			if(Image)
				memcpy(Image, p, *Width**Height);
			if(ImageFile)
			{
				if(WriteBitmap((UDK_U8*)p, *Width, *Height, ImageFile)==0)
					cmd=CMD_ACK_ERROR;
			}
		}
	}
	udk_free(Buffer);
	if(cmd==CMD_ACK_OK)
		return Z_ERROR_OK;
	else
		return Z_ERROR_IO;
}

 int UDK_API Z_GetPINWidth(UDK_HANDLE Handle, int *width)
{
	int i=10;
	char buf[2]={0};
	PEmHandle h = (PEmHandle )Handle;
	WORD cmd = CMD_GET_PINWIDTH;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*width=5;
	while(i--)
	{
		cmd = CMD_GET_PINWIDTH;
		ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 2, 2, h->WaitTimeForACommand);
		/*
		if(cmd==CMD_ACK_ERROR)
		return Z_ERROR_OK;
		else if(cmd==CMD_ACK_UNKNOWN)
		return Z_ERROR_OK;
		*/
		if(cmd==CMD_ACK_OK)
		{
			*width=buf[0];
			h->PINWidth =*width;
			return Z_ERROR_OK;
		}
	}
	if(cmd==CMD_ACK_ERROR)
		return Z_ERROR_OK;
	else if(cmd==CMD_ACK_UNKNOWN)
		return Z_ERROR_OK;
	return Z_ERROR_IO;
}

 int UDK_API Z_QueryUserTemp(UDK_HANDLE Handle, int PIN, int FingerIndex, char* TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;
	PTemplate tmp;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->TmpSize==0 || h->TmpBuffer==NULL) 
	{//??��??????????????????
		return Z_GetUserTmp(Handle, PIN, FingerIndex, TmpData, Size);
	}
	tmp=(PTemplate)h->TmpBuffer;
	PIN=GetPIN1(h, PIN);
	while((unsigned long)tmp<(unsigned long)(h->TmpBuffer+h->TmpSize))
	{
		if(tmp->PIN==PIN && tmp->FingerID==FingerIndex)
		{
			*Size=BiokeyTemplateLength(((UDK_U8*)tmp)+6);
			if(*Size)
				memcpy(TmpData, ((char*)tmp)+6, *Size);
			if(*Size<50)
				printf("zzz");
			return Z_ERROR_OK;
		}
		tmp=(PTemplate)(((char*)tmp)+tmp->Size);
	}
	return Z_ERROR_NO_DATA;
}

 int UDK_API Z_ClearUData(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_DATA;
	char fct_id;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	fct_id=FCT_UDATA;
	ZEMBPRO_SENDCMD(h->emh, &cmd, &fct_id, 1, 1, 3000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
/*
#pragma pack(push)
#pragma pack(1)
typedef struct _UData_{
UDK_U8 Valid;  	//?????��
UDK_U8 Tag;		//?????????
UDK_U16 PIN;		//???????????????
UDK_U16 ValidMinutes; 	//??��??????   ????????
UDK_U16 Reserved;	//
UDK_U32 StartTime;	//??????
UDK_U8 Content[MAX_SMS_CONTENT_SIZE];	//?????????
}TUData, *PUData;	//64 Bytes 
#pragma pack(pop)
*/
/*
 int UDK_API Z_AppendUData(UDK_HANDLE Handle, UDK_U8 Tag, int PIN,
int ValidMinutes, int StartTime, char *Context, int ContextLen)
{
PEmHandle h = (PEmHandle )Handle;
unsigned short cmd=CMD_UDATA_WRQ;
TUData udata;
if(NULL==h)	return Z_ERROR_NOT_INIT;
memset(&udata, 0xff, sizeof(udata));
udata.Tag = Tag;
udata.PIN = PIN;
udata.ValidMinutes=ValidMinutes;
udata.StartTime = StartTime;
memcpy(udata.Content, Context, min(ContextLen,MAX_SMS_CONTENT_SIZE));
ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&udata, sizeof(udata), sizeof(udata), 2000+h->WaitTimeForACommand);
if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
return Z_ERROR_OK;
}

 int UDK_API Z_ReadUData(UDK_HANDLE Handle)
{
PEmHandle h = (PEmHandle )Handle;
int Size;
unsigned short Cmd=CMD_DB_RRQ;
if(NULL==h)	return Z_ERROR_NOT_INIT;
if(h->BufferLen==0 || h->Buffer==NULL)
{
h->BufferLen=2*1024*1024;
h->Buffer=(char*)udk_malloc(h->BufferLen);
}
h->Buffer[0]=6;//UData???
Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,
h->BufferLen, 1, TRUE, h->WaitTimeFor1KData);
if(Cmd==CMD_ACK_OK)
{
h->OLogSize=0;
h->OLogBuffer=NULL;
h->cOLogBuffer=NULL;
h->cALogBuffer=NULL;
h->ALogBuffer=NULL;
h->ALogSize=0;
h->TmpSize=0;
h->TmpBuffer=NULL;
h->cTmpBuffer=NULL;
h->UDataSize=*(int*)(h->Buffer);
h->UDataBuffer=h->Buffer+4;
h->cUDataBuffer=h->UDataBuffer;
return Z_ERROR_OK;
}
else if(Cmd==CMD_ACK_ERROR && Size==0)
{
return Z_ERROR_NO_DATA;
}
else
return Z_ERROR_IO;
}

 int UDK_API Z_GetUData(UDK_HANDLE Handle, UDK_U8 *Tag, int *PIN,
int *ValidMinutes, int *StartTime, char *Context)
{
PEmHandle h = (PEmHandle )Handle;
TUData *udata;

if(NULL==h)	
return Z_ERROR_NOT_INIT;
if(h->UDataSize==0 || h->UDataBuffer==NULL)
{//??��??????????????????
if(Z_ERROR_OK!=Z_ReadUData(Handle)) 
return Z_ERROR_IO;
}
if(h->UDataSize==0 || h->UDataBuffer==NULL) 
return Z_ERROR_NO_DATA;
while(h->cUDataBuffer+sizeof(TUData)<=h->UDataBuffer+h->UDataSize)
{
udata=(PUData)h->cUDataBuffer;
h->cUDataBuffer=(char*)(udata+1);
if(udata->Valid)
{
*Tag=udata->Tag;
*PIN=udata->PIN;
*ValidMinutes=udata->ValidMinutes;
*StartTime=udata->StartTime;
memcpy(Context, udata->Content, MAX_SMS_CONTENT_SIZE);
return Z_ERROR_OK;
}
}
return Z_ERROR_NO_DATA;
}
*/
 int UDK_API Z_ClearSMS(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_DATA;
	char fct_id;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	fct_id=FCT_SMS;
	ZEMBPRO_SENDCMD(h->emh, &cmd,&fct_id, 1, 1, 3000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetCardFun(UDK_HANDLE Handle, int *CardFun)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char *v, Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//????????????
	strcpy(Option, "~IsOnlyRFMachine");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_OK) 
	{//return Z_ERROR_IO;
		v=Option+strlen("~IsOnlyRFMachine")+1;
		*CardFun=atoi(v);
		if(*CardFun==1){   
			return Z_ERROR_OK;
		}
	}
	cmd=CMD_OPTIONS_RRQ;
	memset(Option,0,100);
	strcpy(Option, "~RFCardOn");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100,strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	v=Option+strlen("~RFCardOn")+1;
	*CardFun=atoi(v);
	if(*CardFun==1){
		*CardFun=2;
	}else
		*CardFun=0;
	return Z_ERROR_OK;
}

 int UDK_API Z_SetDeviceCommPwd(UDK_HANDLE Handle, int CommKey)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "COMKey=%d", CommKey);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetDoorState(UDK_HANDLE Handle, int* State)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DOORSTATE_RRQ;
	char DoorState;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, &DoorState, 1, 0, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	*State=DoorState;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetWiegandFmt(UDK_HANDLE Handle,char *WiegandFmt)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "WiegandFmt");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(WiegandFmt, "");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(WiegandFmt, Option+11);
	return Z_ERROR_OK;
}

 int UDK_API Z_SetWiegandFmt(UDK_HANDLE Handle,char *WiegandFmt)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "WiegandFmt=%s", WiegandFmt);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_ReadCustData(UDK_HANDLE Handle, char* CustData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(Option, "~CustData");
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR)
	{
		strcpy(CustData, "");
		return Z_ERROR_OK;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(CustData, Option+10);
	return Z_ERROR_OK;
}

 int UDK_API Z_WriteCustData(UDK_HANDLE Handle, char* CustData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_WRQ;
	char Option[100];
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	sprintf(Option, "~CustData=%s", CustData);
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 100, strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int Z_BeginBatchUpdate(UDK_HANDLE Handle,LONG UpdateFlag)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(strcmp(h->version,VER511)<0 || (h->EmKeyOptions.ZKFPVersion==ZKFPV10 && h->IsTFTMachine && strcmp(h->version,VER660)<0) )
	{
		h->IsBatchUpdate =0;
		return Z_ERROR_UNSUPPORT;
	}
	/*add by zxz 2013-01-05*/
	if(h->UserBuffer != NULL) {
		udk_free(h->UserBuffer);
		h->UserBuffer = NULL;
	}
	//
	h->InnerID = 0;
	if(h->UserIDs != NULL) {
		memset(h->UserIDs, 0, 0x10000);
	}
	//
	h->UserSize = 0;
	h->IsBatchUpdate=1;
	h->IsForceUpdate=(UpdateFlag==1);
	h->IsBatchUpdate=1;
	h->TmpOpBuf=(char*)udk_malloc(1024*1024*10); //1M
	h->TmpOpBufLen=0;
	h->UserInfoOpBuf=(char*)udk_malloc(1024*1024*6);//6M
	h->UserInfoOpBufLen=0;
	h->TmpsBuf=(char*)udk_malloc(1024*1024*70);
	h->TmpsBufLen=0;
	h->BatchTmpUserInfo=(char*)udk_malloc(1024*1024*6);	
	h->BatchTmpSize=0;
	return Z_ERROR_OK;
}

 int Z_CancelBatchUpdate(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;

	h->IsBatchUpdate =0;

	if(h->TmpOpBuf)
		udk_free(h->TmpOpBuf);
	h->TmpOpBuf =NULL;
	h->TmpOpBufLen=0;
	if(h->UserInfoOpBuf)
		udk_free(h->UserInfoOpBuf);
	h->UserInfoOpBuf=NULL;
	h->UserInfoOpBufLen=0;
	if(h->TmpsBuf)
		udk_free(h->TmpsBuf);
	h->TmpsBuf=NULL;
	h->TmpsBufLen=0;

	//??????????????��
	if(h->UserBuffer) 
	{
		udk_free(h->UserBuffer);
		h->UserBufferLen=0; 
	}
	if(h->BatchTmpUserInfo)
	{
		udk_free(h->BatchTmpUserInfo);
		h->BatchTmpSize=0;
	}
	return Z_ERROR_OK;
}

 int Z_BatchUpdate(UDK_HANDLE Handle)
{
	char *data;
	int res=Z_ERROR_UNSUPPORT;
	//FILE *fh;
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(!(h->IsBatchUpdate))
		return Z_ERROR_UNSUPPORT;
	data=(char*)udk_malloc(MAXSIZE);
	if(data)
	{
		int len=MAXSIZE;
		*(UDK_U32*)data=h->UserInfoOpBufLen;
		((UDK_U32*)data)[1]=h->TmpOpBufLen;
		((UDK_U32*)data)[2]=h->TmpsBufLen;
		memcpy(data+12,h->UserInfoOpBuf,h->UserInfoOpBufLen);
		memcpy(data+12+h->UserInfoOpBufLen,h->TmpOpBuf,h->TmpOpBufLen);
		memcpy(data+12+h->UserInfoOpBufLen+h->TmpOpBufLen,h->TmpsBuf,h->TmpsBufLen);
		len=12+h->UserInfoOpBufLen+h->TmpOpBufLen+h->TmpsBufLen;
		/*	
		fh=fopen("C:\\embu.dat", "wb+");
		fwrite(data,len,1,fh);
		fclose(fh);*/
		if(len)
		{
			WORD cmd;
			cmd = CMD_LARGE_FINGER_UPDATEFLAG;
			ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
			cmd=CMD_DISABLEDEVICE;
			res=Z_ERROR_IO;
			ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
			if(cmd!=CMD_ACK_OK)
				res=Z_ERROR_REPEAT_DATA;
			else
				if(ZEMBPRO_SENDDATA(h->emh, data, len, 2500))
				{
					*((int*)data)=UPDATE_BATCHUSERDATA;
					((int*)data)[1]=512*1024;
					cmd=CMD_UPDATE_FIRMWARE;
					ZEMBPRO_SENDCMD(h->emh, &cmd, data, MAXSIZE, 8, 60*60*1000*100);
					if(cmd==CMD_ACK_OK)
					{
						res=Z_ERROR_OK;
						cmd=CMD_REFRESHDATA;
						ZEMBPRO_SENDCMD(h->emh, &cmd, NULL, 0, 0, 1000);
					}
				}
		}
		else
			res=Z_ERROR_PARAM;
		udk_free(data);
	}
	//???????,?????????????????????
	udk_free(h->TmpOpBuf);
	h->TmpOpBuf =NULL;
	h->TmpOpBufLen=0;

	udk_free(h->UserInfoOpBuf);
	h->UserInfoOpBuf=NULL;
	h->UserInfoOpBufLen=0;

	udk_free(h->TmpsBuf);
	h->TmpsBuf=NULL;
	h->TmpsBufLen=0;

	h->IsBatchUpdate =0;

	//??????????????��Henry 2007-3-7???
	if(h->UserBuffer) 
	{
		udk_free(h->UserBuffer);
		h->UserBufferLen=0; 
		h->UserBuffer = NULL;//DSL 2007-6-11
		h->UserSize = 0;//add by zxz 2013-03-06
	}
	if(h->BatchTmpUserInfo)
	{
		udk_free(h->BatchTmpUserInfo);
		h->BatchTmpSize=0;
	}

	return res;
}

 int UDK_API Z_GetData(UDK_HANDLE Handle,int DataFlag, char *DataFile)
{
	char *data;
	int res=Z_ERROR_UNSUPPORT;
	int i=0, position=0, size, dataLen=0;
	char *Buffer;
	FILE *fh;
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	data=(char*)udk_malloc(MAXSIZE);
	if(data)
	{
		WORD cmd;
		res=Z_ERROR_IO;
		cmd=CMD_DB_RRQ;
		Buffer=(char*)udk_malloc(MAXSIZE);
		*(int*)Buffer=DataFlag;
		//????
		size=ZEMBPRO_READDATA(h->emh, &cmd, Buffer,MAXSIZE, 1, h->BlockSize, 2000);
		if(cmd==CMD_ACK_OK)
		{
			dataLen=size-4;
			memset(data, 0xFF, dataLen);
			memcpy(data, Buffer+4, dataLen);
			udk_msleep(1000);
		}
		if(size<=0)
		{
			res=Z_ERROR_NO_DATA;
		}
		else if(cmd!=CMD_ACK_OK)
		{
			res=Z_ERROR_IO;
		}
		else if(size)
		{
			fh=fopen(DataFile, "wb+");
			if(!fh)
				res=Z_ERROR_PARAM;
			else if(fwrite(data,dataLen,1,fh)!=1)
			{
				res=Z_ERROR_PARAM;
			}
			else
			{
				res=Z_ERROR_OK;
			}
			if(fh)
				fclose(fh);
		}
		udk_free(Buffer);			
		udk_free(data);
	}
	return res;
}

//Mifare ??????
 int UDK_API Z_MFWrite(UDK_HANDLE Handle,long PIN,char *TmpsInfoBuf,char* TmpsBuf)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_WRITE_MIFARE;
	char buf[2+3*4+1024*4];
	int i = 0,Size = 0,pinsize = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->PINWidth<=5)
	{
		*(WORD*)buf=PIN;
		pinsize=2;
	}
	else
	{
		*(int*)buf=PIN;
		pinsize=4;
	}
	Size=*(UDK_U16*)(TmpsInfoBuf) + *(UDK_U16*)(TmpsInfoBuf+3) + *(UDK_U16*)(TmpsInfoBuf+6) + *(UDK_U16*)(TmpsInfoBuf+9);
	memcpy(buf+pinsize,TmpsInfoBuf,3*4);
	memcpy(buf+pinsize+4*3,TmpsBuf,1024*4);

	if(ZEMBPRO_SENDDATA(h->emh, buf,  pinsize+3*4+Size, 2500))
	{
		i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 0, 1000);
	}else
		return Z_ERROR_IO;

	//i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 2+3*4+Size, 4000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;	
}

//Mifare ??????
 int UDK_API Z_MFEmpty(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_EMPTY_MIFARE;
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	i=ZEMBPRO_SENDCMD(h->emh, &cmd,NULL, 0, 0,  h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;	
}

 int Z_LastError(void)
{
	return ZEMBPRO_LASTERROR();
	//  1    SUCCESSED
	//  4    ERR_INVALID_PARAM
	//	0    ERR_NO_DATA
	//	-1   ERROR_NOT_INIT
	//	-2   ERROR_IO
	//	-3   ERROR_SIZE
	//	-4   ERROR_NO_SPACE
	//  -100 ERROR_UNSUPPORT
}

//????????????
//????????????,1-5,???????????128 - 128+15
int Z_SetUserInfoEx(UDK_HANDLE Handle, int PIN,int PIN2,int VerifyStyle,char* Reserved)
{
	PEmHandle h = (PEmHandle )Handle;
	int pin, iPin;
	TExtUser extuser;
	char strPin[30] = {0};

	unsigned short cmd=CMD_EXTUSER_WRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset((void*)&extuser,0,sizeof(TExtUser));
	if (h->IsTFTMachine)
	{
		iPin = (PIN > 0)?PIN:PIN2;
		sprintf(strPin, "%d", iPin);
		pin = SSR_GetPIN1(Handle, strPin);
		if (-1 == pin)
		{
			return Z_ERROR_NO_DATA;
		}
		extuser.PIN = pin;
	}
	else
	{
		if(PIN!=0)
		{
			extuser.PIN=PIN;
		}
		else
		{
			pin=Z_QueryUserByPIN2(Handle,PIN2);
			if(pin==0) 
				return Z_ERROR_NO_DATA;
			else
				extuser.PIN =  pin;
		}
	}
	extuser.VerifyStyle=VerifyStyle;
	//ZEMBPRO_SENDCMD(h->emh, &cmd, &extuser, sizeof(TExtUser), sizeof(TExtUser), h->WaitTimeForACommand);
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&extuser, sizeof(TExtUser), sizeof(TExtUser), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

int Z_GetUserInfoEx(UDK_HANDLE Handle, int PIN,int PIN2,int* VerifyStyle,char* Reserved)
{	
	PEmHandle h = (PEmHandle )Handle;
	PExtUser extuser;
	int pin, iPin;
	char extuserbuffer[sizeof(TExtUser)+2] = {0};	
	char strPin[30] = {0};
	unsigned short cmd=CMD_EXTUSER_RRQ;

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	//dsl 2007.10.17
	if (h->IsTFTMachine)
	{
		iPin = (PIN > 0)?PIN:PIN2;
		sprintf(strPin, "%d", iPin);
		pin = SSR_GetPIN1(Handle, strPin);
		if (-1 == pin)
		{
			return Z_ERROR_NO_DATA;
		}		
	}
	else
	{
		if(PIN!=0)
		{
			pin=PIN;
		}
		else
		{
			pin = Z_QueryUserByPIN2(Handle,PIN2);
			if(pin == 0) 
			{
				return Z_ERROR_NO_DATA;
			}
		}
	}
	((UDK_U16*)extuserbuffer)[0]=pin;
	ZEMBPRO_SENDCMD(h->emh, &cmd, extuserbuffer, sizeof(TExtUser)+2, 2, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	extuser = (PExtUser)extuserbuffer;
	*VerifyStyle = extuser->VerifyStyle;
	//??????????????????????
	//memcpy(Reserved,extuser->reserved,sizeof(extuser->reserved));	

	return Z_ERROR_OK;
}

int Z_DeleteUserInfoEx(UDK_HANDLE Handle,int PIN,int PIN2)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_DELETE_EXTUSER;
	UDK_U16 pin = 0, buf = 0;
	int i = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(PIN!=0)
		pin=PIN;
	else
	{
		pin=Z_QueryUserByPIN2(Handle,PIN2);
		if(pin==0) 
			return Z_ERROR_NO_DATA;
	}
	buf=pin;
	//i=ZEMBPRO_SENDCMD(h->emh, &cmd, &buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//???RRS????????? Herny 2006-8-28 begining ??SSR???
//???????????????????????????????1????????????????????????????????????
//********************||****************
//         ???o???????14��???��
//********************||****************
 int UDK_API Z_SSR_GetLog(UDK_HANDLE Handle,char *PIN, unsigned char *VerifyMode, unsigned char *State,
											int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second, int *Workcode)
{
	PEmHandle h = (PEmHandle )Handle;
	SSR_TAttLog log;
	TAttLogx xlog;
	int len;
	TTime t;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->ALogSize==0 || h->Buffer==NULL)
	{//??��??????????????????
		if(Z_ReadLog(Handle,TRUE)!=Z_ERROR_OK) return Z_ERROR_IO;
	}
	if(h->ALogSize==0 || h->ALogBuffer==NULL) return Z_ERROR_NO_DATA;
	if(h->cALogBuffer<h->ALogBuffer+h->ALogSize)
	{
		if(h->libusb_flag == 1)
		{
			len=sizeof(TAttLogx);
			memcpy(&xlog,h->cALogBuffer,len);
			h->cALogBuffer+=len;
			if (PIN) strncpy(PIN,(const char*)xlog.PIN2,10);
			*VerifyMode = xlog.verified;
			*State = xlog.status;
			DecodeTime(xlog.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
			*Workcode = xlog.workcode;
		}
		else
		{
			len=sizeof(SSR_TAttLog);
			memcpy(&log,h->cALogBuffer,len);
			h->cALogBuffer+=len;
			if (PIN) strncpy(PIN,(const char*)log.PIN2,h->PINWidth);
			//*PIN=log.PIN2;
			*VerifyMode=log.verified;
			*State=log.status;
			DecodeTime(log.time_second, &t);
			*Year=t.tm_year; *Month=t.tm_mon; *Day=t.tm_mday;
			*Hour=t.tm_hour; *Minute=t.tm_min; *Second=t.tm_sec;
			*Workcode = log.workcode;
		}
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}

//???14��?????????????,??14��??????????
SSR_PUser SSR_SearchPIN2(UDK_HANDLE Handle, char *UserBuffer, int size, char *PIN2)
{
	int i;
	PEmHandle h = (PEmHandle )Handle;
	UserBuffer+=4; //buffer length
	//if(strcmp(h->version,VER504)<0) return NULL;
	for(i=0;i<(int)(size/sizeof(SSR_TUser));i++)
		if (strcmp(((SSR_PUser)(UserBuffer))[i].PIN2,PIN2) == 0) return ((SSR_PUser)UserBuffer)+i;
	//if(((PUser)(UserBuffer))[i].PIN2==PIN2) return ((PUser)UserBuffer)+i;
	return NULL;
}
//???????PIN
int SSR_QueryFreeUserID(UDK_HANDLE Handle, char *PIN2)
{
	int i,size;
	PEmHandle h = (PEmHandle )Handle;
	char *UserBuffer;
	//dsl 2007.10.31
	//char *UserIDs;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return 1;
	}
	//dsl 2007.10.31
	if (h->UserSize <= 0)
	{
		//???????????????????		
		h->InnerID++;
		return h->InnerID;
	}
	else
	{
		UserBuffer=h->UserBuffer+4;
		//dsl 2008.7.26
		if (!h->UserIDs)
		{
			h->UserIDs = (char*)udk_malloc(0x10000);
			if (!h->UserIDs)
			{
				return 0;
			}
			memset(h->UserIDs, 0, 0x10000);
		}
		//UserIDs=udk_malloc(0x10000);
		//memset(UserIDs, 0, 0x10000);
		size=h->UserSize;
		for(i=0;i<(int)(size/sizeof(SSR_TUser));i++)
			h->UserIDs[((SSR_PUser)(UserBuffer))[i].PIN]=1;
		//i=0;
		for(i=1;i<0xFFFF;i++)
		{
			if(h->UserIDs[i]==0)
			{
				h->UserIDs[i] = 1;//dsl 2007.10.31
				break;
			}
		}
		//udk_free(UserIDs);
		h->InnerID = i;//dsl 2007.10.31.??z_setuserinfoex????
		return i;
	}
}
//SSR get all user info
//?????????????????????????????????1????????????????????????????????????
 int UDK_API SSR_Z_GetUserInfo(UDK_HANDLE Handle,int *PIN, char *PIN2, char *AName, int *Privillege,
												 int *Valid, char *Password, char *Card,int *Group,int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK)
		{
			return Z_ERROR_IO;
		}
	}
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{
		return Z_ERROR_NO_DATA;
	}
	*PIN = 0;
	while(h->cUserBuffer<h->UserBuffer+h->UserSize)
	{		
		SSR_PUser u=(SSR_PUser)(h->cUserBuffer);
		h->cUserBuffer=(char*)(u+1);

		*PIN=u->PIN;
		h->lastpin = u->PIN;
		if(u->PIN == 0)//�����û�,��ӦFX10���� zxz2013-06-15
			continue;
		if(PIN2)
		{
			strncpy(PIN2,u->PIN2,h->PINWidth);
			PIN2[h->PINWidth]=0;
		}
		if(AName)
		{
			//strncpy(Name,u->Name, sizeof(u->Name));
			if(AName) strncpy(AName,u->Name, 24); AName[24]=0;
			//Name[24]=0;
		}
		if(Privillege)
		{
			if (!h->bNewFirmware)
			{
				if(((u->Privillege)>>1)==7)
				{
					*Privillege=3;
				}else if(((u->Privillege)>>1)==5)
				{
					*Privillege=4;
				}else if(((u->Privillege)>>1)==3)
				{
					*Privillege=2;
				}else if(((u->Privillege)>>1)==1) 
				{
					*Privillege=1;
				}else if(((u->Privillege)>>1)==0) 
				{
					*Privillege=0;
				}else if (u->Privillege == 255) //?????????
				{
					*Privillege = -1;
				}else
				{
					*Privillege=u->Privillege;
				}
			}
			else
			{
				*Privillege=u->Privillege;
			}
			
		}
		if(Valid)
		{
			*Valid=!(u->Privillege & 1);
		}
		if(Password)
		{
			strncpy(Password, u->Password, 8);
		}
		Password[8]=0;
		if(Card)
		{
			memcpy(Card, u->Card, sizeof(u->Card));
		}
		if(Group)
		{
			*Group=u->Group;
		}
		//if(TZs) memcpy(TZs,u->TimeZones,sizeof(u->TimeZones)); 
		if(TZs)
		{
			TZs[0]=u->TimeZones[0];
			TZs[1]=u->TimeZones[1];
			TZs[2]=u->TimeZones[2];
			TZs[3]=u->TimeZones[3];
		}
		break;
	}
	if(*PIN == 0)
	{
		return Z_ERROR_NO_DATA;
	}
	return Z_ERROR_OK;
}

//??PIN214��?????PIN
//???????? HADLE: ??????
//         PIN2:14��??
//????: ???????PIN,?????? -1
int SSR_GetPIN1(UDK_HANDLE Handle, char * PIN2)
{
	PEmHandle h = (PEmHandle )Handle;
	SSR_PUser u;

	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	u=SSR_SearchPIN2(h, h->UserBuffer, h->UserSize, PIN2);
	if(u)
	{
		return u->PIN; 
	}
	else if (h->InnerID)
	{
		//dsl 2007.10.31
		return h->InnerID;
	}
	else 
	{
		return -1;
	}
}
/*
??????��??????????????????
char *TmpData
[out] Pointer to the memory space where template raw data will be saved
int *Size
[In/Out] On input, Size parameter is interpreted as total size of allocated memory pointed by TmpData. On return, this parameter will be equal to the total
length of user template
*/

 int UDK_API SSR_Z_GetUserTmp(UDK_HANDLE Handle, char *PIN, int FingerIndex, 
												char *TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTEMP_RRQ;
	int AtempUserID;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//???PIN
	AtempUserID=SSR_GetPIN1(h,PIN);
	//dsl 2008.7.19
	if(AtempUserID > 0) 
	{
		*(WORD*)TmpData=AtempUserID;
	}
	else if (-1 == AtempUserID)
	{
		//??????????,?????????????????????????????��????????????????-1?????????????��?
		memset(h->UserBuffer, 0, h->UserBufferLen);
		Z_ReadUserInfo(Handle);
		AtempUserID=SSR_GetPIN1(h,PIN);
		if (-1 == AtempUserID)
		{
			return Z_ERROR_NO_DATA;
		}
		*(WORD*)TmpData=AtempUserID;
	}
	else
	{
		return Z_ERROR_NO_DATA;
	}

	TmpData[2]=FingerIndex;
	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
		*Size=ZEMBPRO_READDATA1(h->emh,&cmd,TmpData,*Size,3,h->BlockSize,h->WaitTimeFor1KData);
	else
		*Size=ZEMBPRO_SENDCMD(h->emh, &cmd, TmpData, *Size, 3, h->WaitTimeFor1KData);

	if(cmd==CMD_ACK_ERROR)
	{
		return Z_ERROR_NO_DATA;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//????��????????????1?????????????	add by wtj 2009-11-5
 int UDK_API Z_GetUserTmpEx(UDK_HANDLE Handle, char *PIN, int FingerIndex,int *Flag,char *TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;	
	unsigned short cmd=CMD_USERTEMP_EX_RRQ;
	int AtempUserID;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (h->IsTFTMachine)
	{
		AtempUserID=SSR_GetPIN1(h,PIN);
	}
	else 
	{
		AtempUserID=GetPIN1(h,atoi(PIN));
	}


	if(AtempUserID > 0) 
	{
		*(WORD*)TmpData=AtempUserID;
	}
	else if ((-1 == AtempUserID) && (h->IsTFTMachine))
	{
		//??????????,?????????????????????????????��????????????????-1?????????????��?
		memset(h->UserBuffer, 0, h->UserBufferLen);
		Z_ReadUserInfo(Handle);
		AtempUserID=SSR_GetPIN1(h,PIN);
		if (-1 == AtempUserID)
		{
			return Z_ERROR_NO_DATA;
		}
		*(WORD*)TmpData=AtempUserID;
	}
	else
	{
		return Z_ERROR_NO_DATA;
	}
	TmpData[2]=FingerIndex;
	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
	{
		*Size=ZEMBPRO_READDATA1(h->emh,&cmd,TmpData,*Size,3,h->BlockSize,h->WaitTimeFor1KData);		
	}
	else
	{
		*Size=ZEMBPRO_SENDCMD(h->emh, &cmd, TmpData, *Size, 3, h->WaitTimeFor1KData);

	}
	//get fingerprint flag
	if ((cmd==CMD_ACK_OK) && (h->IsTFTMachine))//&& ((h->EmKeyOptions.ZKFPVersion)!=ZKFPV10)
	{
		*Flag=*((UDK_U8*)(TmpData+*Size-1));
	}	

	*Size -= 1;

	if(cmd==CMD_ACK_ERROR)
	{
		return Z_ERROR_NO_DATA;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//??????��??????PIN???????????.???????��?,  ????Flag??��??????????add by wtj 2009-11-5
 int UDK_API Z_QueryUserTempEx(UDK_HANDLE Handle, char *PIN, int FingerIndex, int * Flag, char* TmpData, int *Size)
{                              
	PEmHandle h = (PEmHandle )Handle;
    PTemplate tmp={0};
    PTmpX20 tmpX={0};
	UDK_U16 PINTemp;
	char *dataBuf=NULL;
	int temlen;
	int ret;
	int sizeOffset=0;

	sizeOffset = 6;
	if(NULL==h)	
	{
		return Z_ERROR_NOT_INIT;
	}
	if(h->TmpSize==0 || h->TmpBuffer==NULL )
	{//??��??????????????????
		ret=Z_GetUserTmpEx(Handle, PIN, FingerIndex,Flag, TmpData, Size);
		return ret;
	}
	if(h->libusb_flag == 1)
		tmpX = (PTmpX20)h->TmpBuffer;
	else
		tmp=(PTemplate)h->TmpBuffer;

	if (h->IsTFTMachine)
	{
		PINTemp=(UDK_U16)SSR_GetPIN1(h, PIN);
	}
	else
	{
		PINTemp=(UDK_U16)GetPIN1(h, atoi(PIN));
	}
	if(!PINTemp)
	{
		return Z_ERROR_NO_DATA;
	}
	
	if(h->isfingerquick == 1)
	{
		//PINTemp = h->lastpin;
		switch(FingerIndex)
		{
		case 0:
			sizeOffset = h->fingerquicksearch[PINTemp].index0;
			break;
		case 1:
			sizeOffset = h->fingerquicksearch[PINTemp].index1;
			break;
		case 2:
			sizeOffset = h->fingerquicksearch[PINTemp].index2;
			break;
		case 3:
			sizeOffset = h->fingerquicksearch[PINTemp].index3;
			break;
		case 4:
			sizeOffset = h->fingerquicksearch[PINTemp].index4;
			break;
		case 5:
			sizeOffset = h->fingerquicksearch[PINTemp].index5;
			break;
		case 6:
			sizeOffset = h->fingerquicksearch[PINTemp].index6;
			break;
		case 7:
			sizeOffset = h->fingerquicksearch[PINTemp].index7;
			break;
		case 8:
			sizeOffset = h->fingerquicksearch[PINTemp].index8;
			break;
		case 9:
			sizeOffset = h->fingerquicksearch[PINTemp].index9;
			break;
		default:
			sizeOffset = -1;
			break;
		}

		if(sizeOffset > 5)
		{
			tmp=(PTemplate)(((char*)tmp)+sizeOffset-6);
			*Size= tmp->Size -6;	//BiokeyTemplateLength(((char*)tmp)+sizeOffset);
			if(*Size)
			{
				*Flag=tmp->Valid;
				memcpy(TmpData, ((char*)tmp)+6, *Size);	
			}
			return Z_ERROR_OK;
		}
		else
		{
			return Z_ERROR_NO_DATA;
		}
	}

	if(h->libusb_flag == 1)
	{
		while((unsigned long)tmpX<(unsigned long)(h->TmpBuffer+h->TmpSize))
		{	
			if(tmpX->PIN==PINTemp && tmpX->FingerID==FingerIndex)
			{
				*Flag=tmpX->Valid;
				*Size = tmpX->Size;
				memcpy(TmpData, tmpX->Template, tmpX->Size);	
				return Z_ERROR_OK;
			}
			tmpX=(PTmpX20)(((char*)tmpX) + sizeof(TTmpX20));
		}
	}
	else
	{
		while((unsigned long)tmp<(unsigned long)(h->TmpBuffer+h->TmpSize))
		{	
			if(tmp->PIN==PINTemp && tmp->FingerID==FingerIndex)
			{
				*Size= tmp->Size -6;	//BiokeyTemplateLength(((char*)tmp)+sizeOffset);
				if(*Size)
				{
					*Flag=tmp->Valid;
					memcpy(TmpData, ((char*)tmp)+sizeOffset, *Size);	
				}
				return Z_ERROR_OK;
			}
			tmp=(PTemplate)(((char*)tmp)+tmp->Size);
		}
	}
	return Z_ERROR_NO_DATA;
}

//??????��??????PIN???????????.???????��?
 int UDK_API SSR_Z_QueryUserTemp(UDK_HANDLE Handle, char *PIN, int FingerIndex, char* TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;
	PTemplate tmp;
	UDK_U16 PINTemp;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->TmpSize==0 || h->TmpBuffer==NULL)
	{//??��??????????????????
		return SSR_Z_GetUserTmp(Handle, PIN, FingerIndex, TmpData, Size);
	}
	tmp=(PTemplate)h->TmpBuffer;
	PINTemp=(UDK_U16)SSR_GetPIN1(h, PIN);
	if(!PINTemp) return Z_ERROR_NO_DATA;

	while((unsigned long)tmp<(unsigned long)(h->TmpBuffer+h->TmpSize))
	{	
		if(tmp->PIN==PINTemp && tmp->FingerID==FingerIndex)
		{
			*Size= tmp->Size -6;	//BiokeyTemplateLength(((char*)tmp)+6);
			if(*Size)
				memcpy(TmpData, ((char*)tmp)+6, *Size);
			return Z_ERROR_OK;
		}
		tmp=(PTemplate)(((char*)tmp)+tmp->Size);
	}
	return Z_ERROR_NO_DATA;
}

//upload user info ,2006-8-30

/*
???????��?SSR SDK.?????????????????????????????????????????????4????��?
???AccTimeZones??AccGroup??
*/
 int UDK_API SSR_Z_SetUserInfo(UDK_HANDLE Handle, char *PIN2, char *Name,  int Privillege,
												 int Valid, char *Password, char *Card,int Group, int *TZs)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USER_WRQ;
	SSR_TUser u; 
	SSR_PUser user=NULL;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	
	//setuserinfo flag
	memset((void*)&u,0,sizeof(SSR_TUser));
	if(h->UserBuffer==NULL||h->UserBufferLen==0) Z_ReadUserInfo(Handle);
	user=SSR_SearchPIN2(Handle, h->UserBuffer, h->UserSize, PIN2);
	if(user==NULL)
	{
		u.PIN=SSR_QueryFreeUserID(Handle, PIN2);
	}
	//u?????????,2006-9-11
	memcpy(u.PIN2,PIN2,strlen(PIN2));
	//memcpy(u.PIN2,PIN2,24);
	if(user!=NULL)
	{
		u.PIN=user->PIN;
	}
	if(Name)		
		memcpy(u.Name,Name,24);
	if(Password)
		memcpy(u.Password,Password, 8);

	if (!h->bNewFirmware)
	{
		if(Privillege==2)
			Privillege=PRIVILLEGE2;
		else if(Privillege==1)
			Privillege=PRIVILLEGE1;
		else if(Privillege==3)
			Privillege=PRIVILLEGE3;
	}
	u.Privillege=Privillege | (Valid==0);
	//henry 2006-11-14 Group tzs add for SSR
	u.Group=Group; 
	//if(TZs) memcpy(u.TimeZones,TZs,sizeof(TZs)); 
	if(TZs)
	{
		u.TimeZones[0]=(TZs[0]); //(int*) ????????????(0:?�1:?????)
		u.TimeZones[1]=(TZs[1]); //????1
		u.TimeZones[2]=(TZs[2]); //????2
		u.TimeZones[3]=(TZs[3]); //????3
	}
	if(Card) memcpy(u.Card, Card, sizeof(u.Card));

	if(h->IsBatchUpdate){
		*(UDK_U8*)(h->UserInfoOpBuf+h->UserInfoOpBufLen)=2;	//???????
		memcpy(h->UserInfoOpBuf+h->UserInfoOpBufLen+1,&u,sizeof(SSR_TUser));//??????
		h->UserInfoOpBufLen+=sizeof(SSR_TUser)+1;
		/*??????add by zxz 2013-01-05*/
		if(NULL==user) 
		{
			h->UserSize+=sizeof(SSR_TUser);
			user=((SSR_PUser)(h->UserBuffer+4))+(h->UserSize/sizeof(SSR_TUser)-1);
		}
		memcpy(user, &u, sizeof(SSR_TUser));
		return Z_ERROR_OK;
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&u, sizeof(SSR_TUser), sizeof(SSR_TUser), 2000+h->WaitTimeForACommand);
	//??????
	if(cmd==CMD_ACK_OK)
	{
		if(NULL==user) 
		{
			h->UserSize+=sizeof(SSR_TUser);
			user=((SSR_PUser)(h->UserBuffer+4))+(h->UserSize/sizeof(SSR_TUser)-1);
		}
		memcpy(user, &u, sizeof(SSR_TUser));//??????????		
	}
	else
		return Z_ERROR_IO;

	return Z_ERROR_OK;
}

//upload user template 2006-8-30
//?????????????????
//?��???????????????????????????1??????????????????0???????????
//??????????????????10?
 int UDK_API SSR_Z_SetUserTmp(UDK_HANDLE Handle, char *PIN, int FingerIndex, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTEMP_WRQ;
	char buf[2048];
	char *dataBuf=NULL;
	int i,Size=0,dataBufLen=0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset(buf,0,2048);

	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
	{
		//the 10.0 fp algrithm don't support 9.0 template
		if(FingerIndex!=ZKFPV10_FINGER_INDEX)	return Z_ERROR_UNSUPPORT;	
		if((Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+5)))>0) return Z_ERROR_UNSUPPORT;	
		dataBufLen = ((UDK_U8)TmpData[8])*256+(UDK_U8)TmpData[9];
		if(dataBufLen>TMP_BUF_LEN) return Z_ERROR_SIZE;
		dataBuf = (char*)udk_malloc(TMP_BUF_LEN);
		memcpy(dataBuf,TmpData,dataBufLen);
	}
	else
	{
		Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+5));
		if(Size>1024-(8+5))
		{
			Size=SetBiokeyTemplateLen((UDK_U8*)TmpData, 1024-(8+5));
			if(Size==0)
				return Z_ERROR_SIZE;
		}
		//the 9.0 fp algrithm don't support 1.0 template
		if(Size<50) return Z_ERROR_SIZE;
	}
	*(WORD*)buf=SSR_GetPIN1(h, PIN);
	buf[2]=(char)FingerIndex;
	*(UDK_U16*)(buf+3)=Size;
	if(h->IsBatchUpdate){
		if(h->IsForceUpdate)
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=2;
		else
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=1;//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf; //UserID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=(char)FingerIndex;	//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=h->TmpsBufLen;//Offset
		h->TmpOpBufLen+=8;

		*(UDK_U16*)(h->TmpsBuf+h->TmpsBufLen)=Size;	//??�??
		memcpy(h->TmpsBuf+h->TmpsBufLen+2,buf+5,Size);//???
		h->TmpsBufLen+=Size+2;								//??????????
		if(dataBuf)	udk_free(dataBuf);
		return Z_ERROR_OK;
	}

	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
		i=ZEMBPRO_SENDCMDDATA(h->emh, &cmd, dataBuf, dataBufLen, buf , 5, h->WaitTimeFor1KData);
	else
		i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, Size+5, 1000+h->WaitTimeForACommand);
	if(dataBuf)	udk_free(dataBuf);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}
//????????????????? ????��????? add by wtj
 int UDK_API Z_SetUserTmpEx(UDK_HANDLE Handle, char *PIN, int FingerIndex,int Flag, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERTEMP_EX_WRQ;
	char buf[2048];
	char *dataBuf=NULL;
	int i,Size=0,dataBufLen=0;
	int sizeOffset=0;
	int tmpPIN = 0; //add by zhc 

	if(NULL==h)
	{	
		return Z_ERROR_NOT_INIT;
	}

	memset(buf,0,2048);

	sizeOffset = 6;
	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
	{
		//the 10.0 fp algrithm don't support 9.0 template	
		if((Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+sizeOffset)))>0) return Z_ERROR_UNSUPPORT;	
		dataBufLen = ((UDK_U8)TmpData[8])*256+(UDK_U8)TmpData[9];
		if(dataBufLen>TMP_BUF_LEN || dataBufLen<128) return Z_ERROR_SIZE;
		dataBuf = (char*)udk_malloc(TMP_BUF_LEN);
		memcpy(dataBuf,TmpData,dataBufLen);
		Size = dataBufLen;
	}
	else
	{
		Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+sizeOffset));
		if(Size>MAXVALIDTMPSIZE)	//equal to zem500
		{
			Size=SetBiokeyTemplateLen((UDK_U8*)TmpData, MAXVALIDTMPSIZE);
			if(Size==0)
				return Z_ERROR_SIZE;
		}
		//the 9.0 fp algrithm don't support 1.0 template
		if(Size<50) 
			return Z_ERROR_SIZE;
	}
	if (h->IsTFTMachine)
	{
		*(WORD*)buf=SSR_GetPIN1(h, PIN);
	}
	else
	{		
		tmpPIN=atol(PIN); //add by zhc for bw_firm pin
		*(WORD*)buf=GetPIN1(h, tmpPIN);
	}
	buf[2]=(char)FingerIndex;
	*(buf+3)=Flag;
	*(UDK_U16*)(buf+4)=Size;


	if(h->IsBatchUpdate){
		if(h->IsForceUpdate)
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=2;
		else
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=1;//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*((WORD*)buf); //UserID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=(char)((FingerIndex&0x0f) | ((Flag&0x0f)<<4));	//FingerID& flag for duress fp,only TFT Ver 6.60 version later support, 2009.11.18
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=h->TmpsBufLen;//Offset
		h->TmpOpBufLen+=8;

		*(UDK_U16*)(h->TmpsBuf+h->TmpsBufLen)=Size;	//??�??
		if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
			memcpy(h->TmpsBuf+h->TmpsBufLen+2,dataBuf,Size);//???
		else
			memcpy(h->TmpsBuf+h->TmpsBufLen+2,buf + sizeOffset ,Size);//???
		h->TmpsBufLen+=Size+2;								//??????????
		if(dataBuf)	udk_free(dataBuf);
		return Z_ERROR_OK;
	}

	if(h->EmKeyOptions.ZKFPVersion==ZKFPV10)
		i=ZEMBPRO_SENDCMDDATA(h->emh, &cmd, dataBuf, dataBufLen, buf , sizeOffset, h->WaitTimeFor1KData);
	else
		i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, Size+sizeOffset, 1000+h->WaitTimeForACommand);
	if(dataBuf)	udk_free(dataBuf);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}



//???PIN??????????????????
 int UDK_API SSR_Z_QueryUserInfo(UDK_HANDLE Handle, char* PIN2, char *Name,  int *Privillege,
												   int *Valid, char *Password,char *Card,int *Group,int *TZs, int *InnerPin)
{
	int i=0;
	PEmHandle h = (PEmHandle )Handle;
	SSR_PUser u = NULL;
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(h->UserSize==0 || h->UserBuffer==NULL)
	{//??��??????????????????
		if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK)
		{
			return Z_ERROR_IO;
		}
	}	
	u=SSR_SearchPIN2(h, h->UserBuffer,h->UserSize,PIN2);
	if(!u)
	{
		return Z_ERROR_NO_DATA;
	}
	if(Name)
	{
		strncpy(Name,u->Name, 24); 
		Name[24]=0;
	}
	//dsl 2007.11.9
	*InnerPin = u->PIN;
	if(Privillege)
	{
		if(!h->bNewFirmware)
		{
			if(((u->Privillege)>>1)==7)
			{
				*Privillege=3;
			}else if(((u->Privillege)>>1)==5)
			{
				*Privillege=4;
			}else if(((u->Privillege)>>1)==3)
			{
				*Privillege=2;
			}else if(((u->Privillege)>>1)==1) 
			{
				*Privillege=1;
			}else if(((u->Privillege)>>1)==0) 
			{
				*Privillege=0;
			}else if (u->Privillege == 255) //?????????
			{
				*Privillege = -1;
			}else
			{
				*Privillege=u->Privillege;
			}
		}
		else
		{
			*Privillege=u->Privillege;
		}
		
	}
	if(Valid)
	{
		*Valid=!(u->Privillege & 1);
	}
	if(Password)
	{
		strncpy(Password, u->Password, 8); //Password[5]=0;
	}
	if(Card)
	{
		memcpy(Card, u->Card, sizeof(u->Card));
	}
	if(Group)
	{
		*Group=u->Group;
	}
	//if(TZs) memcpy(TZs,u->TimeZones,sizeof(u->TimeZones));
	if(TZs)
	{
		TZs[0]=u->TimeZones[0];
		TZs[1]=u->TimeZones[1];
		TZs[2]=u->TimeZones[2];
		TZs[3]=u->TimeZones[3];
	}
	return Z_ERROR_OK;
}

//????????????
 int UDK_API SSR_Z_DelUser(UDK_HANDLE Handle, char* PIN)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DELETE_USER;
	int i;
	//UDK_U16 PIN1;//dsl 2008.10.31
	int PIN1;//dsl 2008.10.31
	SSR_PUser user=(SSR_PUser)udk_malloc(sizeof(SSR_TUser));
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	PIN1=SSR_GetPIN1(h, PIN);
	if(h->IsBatchUpdate){
		user->PIN =PIN1;
		(h->UserInfoOpBuf+h->UserInfoOpBufLen)[0]=0;	//???????
		memcpy(h->UserInfoOpBuf+h->UserInfoOpBufLen+1,user,sizeof(SSR_TUser));//??????
		h->UserInfoOpBufLen+=sizeof(SSR_PUser)+1;

		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=PIN1;	//???ID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=0xFF;					//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=-1;	//Offset
		h->TmpOpBufLen+=8;
		return Z_ERROR_OK;
	}
	//dsl 2008.10.31
	if (PIN1 == -1)//????????buffer?��?????????
	{
		return Z_ERROR_NO_DATA;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&PIN1, 0, 2, 2000+h->WaitTimeForACommand);
	//if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;//dsl 2008.10.31,???????????????????????????i=2,??
	//????.
	if(cmd==CMD_ACK_ERROR) return Z_ERROR_NO_DATA;//dsl 2008.10.31
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
//?????????????�^
//???????????????0???????????1???????????
 int UDK_API SSR_Z_DelUserTmp(UDK_HANDLE Handle, char* PIN, int FingerIndex)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DELETE_USERTEMP;
	char buf[6];
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	*(WORD*)buf=SSR_GetPIN1(h, PIN);
	buf[2]=FingerIndex;
	if(h->IsBatchUpdate){
		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf;	//???ID
		(h->TmpOpBuf+h->TmpOpBufLen)[3]=(char)FingerIndex;		//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+4)=-1;	//Offset
		h->TmpOpBufLen+=8;
		return Z_ERROR_OK;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 3, 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//work code 2006-10-17 
//henry,workcode modify ,and the function for  manage workcode,2006-10-17
//???
 int UDK_API Z_GetWorkCode(UDK_HANDLE Handle, int WorkCodeID,int *AWorkCode)
{
	PEmHandle h = (PEmHandle )Handle;
	PWorkCode MineWordCode;
	char WorkCodeBuffer[sizeof(TWORKCODE)+2];
	//TTime t;
	unsigned short cmd=CMD_WorkCode_RRQ;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	((UDK_U16*)WorkCodeBuffer)[0]=(unsigned short)WorkCodeID;
	ZEMBPRO_SENDCMD(h->emh, &cmd, WorkCodeBuffer, sizeof(WorkCodeBuffer)+2, 2, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	MineWordCode=(PWorkCode)WorkCodeBuffer;
	//memcpy(AWorkCode, MineWordCode->WORKCODE,sizeof(MineWordCode->WORKCODE));
	*AWorkCode=MineWordCode->WORKCODE;
	return Z_ERROR_OK;
}
//????
 int UDK_API Z_SetWorkCode(UDK_HANDLE Handle, int WorkCodeID,int AWorkCode)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_WorkCode_WRQ;
	TWORKCODE MineWorkCode;

	if(NULL==h)	return Z_ERROR_NOT_INIT;

	memset((void*)&MineWorkCode,0,sizeof(TWORKCODE));
	MineWorkCode.WORKID=(unsigned short)WorkCodeID;
	MineWorkCode.WORKCODE=AWorkCode; 
	MineWorkCode.Reserver[0]=0;
	MineWorkCode.Reserver[1]=0;
	//ZEMBPRO_SENDCMD(h->emh, &cmd, &MineWorkCode, sizeof(MineWorkCode), sizeof(MineWorkCode), h->WaitTimeForACommand);
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&MineWorkCode, sizeof(MineWorkCode), sizeof(MineWorkCode), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
//???
 int UDK_API Z_DeleteWorkCode(UDK_HANDLE Handle, int WorkCodeID)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_DELETE_WorkCode;
	UDK_U16 buf = 0;
	int i = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	buf=(unsigned short)WorkCodeID;
	//i=ZEMBPRO_SENDCMD(h->emh, &cmd, &buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&buf, 0, sizeof(UDK_U16), 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//???
 int UDK_API Z_ClearWorkCode(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_CLEAR_DATA;
	char fct_id;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	fct_id=CMD_Clear_WordCode;
	ZEMBPRO_SENDCMD(h->emh, &cmd, &fct_id, 1, 1, 3000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
// work code end 2006-10-17 
//henry 2006-11-10 add for ssr read att ruluer table and department
//??????????
//char *cAttRuleBuffer,*aAttRuleBuffer,*cDPTBuffer,*aDPTBuffer;
//int AttRulueLen,DPTBufferLen;
//this begin
 int UDK_API Z_SSR_ReadAttRule(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd=CMD_ATTRule_RRQ;
	//char *s;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		h->BufferLen=2*1024*1024*3;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}
	Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer, h->BufferLen, 0, TRUE, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		h->AttRulueLen=*(int*)(h->Buffer);
		h->aAttRuleBuffer=h->Buffer+4; 
		h->cAttRuleBuffer=h->aAttRuleBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

//???????
 int UDK_API Z_SSR_ReadDPT(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd=CMD_DTP_RRQ;
	//char *s;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		//h->BufferLen=2*1024*1024;
		h->BufferLen=2*1024*1024*3;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}
	Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer, h->BufferLen, 0, TRUE, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		h->DPTBufferLen=*(int*)(h->Buffer);
		h->aDPTBuffer=h->Buffer+4; 
		h->cDPTBuffer=h->aAttRuleBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

//???????????1,????????2,?????3,??????? ??4,?????��?,5,???
//char *cAttRuleBuffer,*aAttRuleBuffer,*cDPTBuffer,*aDPTBuffer;
//int AttRulueLen,DPTBufferLen;
//this begin
 int UDK_API Z_SSR_SaveDate(UDK_HANDLE handle,char *FilePath,int FileFlag)
{	
	PEmHandle h=(PEmHandle)handle;
	switch(FileFlag)
	{
	case 1:
		{
			if(h->cALogBuffer&&h->ALogSize>0)
			{			
				if ((SaveDataToFile(FilePath,h->cALogBuffer,h->ALogSize)==h->ALogSize))
				{
					return Z_ERROR_OK; //??????
				}
				else
					return Z_ERROR_IO; //???????
			}
			else
				return Z_ERROR_NO_DATA; //?????
		}
		break;
	case 2:
		{
			if(h->UserBuffer&&h->UserSize>0)
			{			
				if ((SaveDataToFile(FilePath,h->cUserBuffer,h->UserSize)==h->UserSize))
				{
					return Z_ERROR_OK; //??????
				}
				else
					return Z_ERROR_IO; //???????
			}
			else
				return Z_ERROR_NO_DATA; //?????
		}
		break;
	case 3: //
		{
			if(h->cAttRuleBuffer&&h->AttRulueLen>0)
			{			
				if ((SaveDataToFile(FilePath,h->cAttRuleBuffer,h->AttRulueLen)==h->AttRulueLen))
				{
					return Z_ERROR_OK; //??????
				}
				else
					return Z_ERROR_IO; //???????
			}
			else
				return Z_ERROR_NO_DATA; //?????
		}
		break;
	case 4: //???��???��?
		{
			if(h->cDPTBuffer&&h->DPTBufferLen>0)
			{			
				if ((SaveDataToFile(FilePath,h->cDPTBuffer,h->DPTBufferLen)==h->DPTBufferLen))
				{
					return Z_ERROR_OK; //??????
				}
				else
					return Z_ERROR_IO; //???????
			}
			else
				return Z_ERROR_NO_DATA; //?????
		}
		break;
	case 5: //??????
		{
			if(h->cTurnBuffer&&h->TrunBufferLen>0)
			{			
				if ((SaveDataToFile(FilePath,h->cTurnBuffer,h->TrunBufferLen)==h->TrunBufferLen))
				{
					return Z_ERROR_OK; //??????
				}
				else
					return Z_ERROR_IO; //???????
			}
			else
				return Z_ERROR_NO_DATA; //?????

		}
		break;
	default:
		return Z_ERROR_NO_DATA;
	}
}

//???? ??? ????,????????????????????-1.2006-11-10
int SaveDataToFile(char *FilePath,char *AData,int DataLen)
{
	FILE *f;
	int test;
	unlink(FilePath);
	f=fopen(FilePath,"wb");
	if (!f) return -1; 
	if ((test=fwrite(AData,DataLen,1,f))==1)
	{
		fclose(f);
		return DataLen;
	}
	else
	{
		fclose(f);
		return -1;
	}
}

//????????? 
//*cTurnBuffer,aTurnBuffer;
 int UDK_API Z_SSR_ReadTurn(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd=CMD_Turn_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		h->BufferLen=2*1024*1024*3;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}
	Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer, h->BufferLen, 0, TRUE, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		h->TrunBufferLen=*(int*)(h->Buffer); 
		h->aTurnBuffer=h->Buffer+4; 
		h->cTurnBuffer=h->aTurnBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

//henry 2006-11-10 add for ssr read att ruluer table and department
//??????????
//char *cAttRuleBuffer,*aAttRuleBuffer,*cDPTBuffer,*aDPTBuffer;
//int AttRulueLen,DPTBufferLen;
// this end

//ssr output att html 2006-11-15
//?��????????????????��??????????0??????????????????HTML.
//void Openattdb(char *AttFile,char *UserFile,char * deptFile,char *TimeClassFile,char *AttRuleFile,char *TempPath)
 int UDK_API Z_SSR_OutPutHtml(UDK_HANDLE Handle,char* pin,char *AttFile,char *UserFile,char *DeptFile,char * TimeClassFile,
												int BYear, int BMonth, int BDay,int BHour, int BMinute, int BSecond,
												int EYear, int EMonth, int EDay, int EHour, int EMinute, int ESecond,
												char *OutFileName,char *TempPath,char *AttruleFile,int HTMLFlag,char *RepName)
{
	struct tm tmt;
	PEmHandle h = (PEmHandle )Handle;
	SSR_PUser user;
	SSR_PUser u;
	//UDK_U16 minePIN;
	char  *SDKattrule;
	UDK_U32 d1,d2;
	tmt.tm_hour=BHour;
	tmt.tm_mday=BDay;
	tmt.tm_min=BMinute;
	tmt.tm_mon=BMonth;
	tmt.tm_sec=BSecond;
	tmt.tm_year=BYear;
	d1=EncodeTime(&tmt);
	tmt.tm_hour=EHour;
	tmt.tm_mday=EDay;
	tmt.tm_min=EMinute;
	tmt.tm_mon=EMonth;
	tmt.tm_sec=ESecond;
	tmt.tm_year=EYear;
	d2=EncodeTime(&tmt);

	Openattdb(AttFile,UserFile,DeptFile,TimeClassFile,AttruleFile,TempPath);
	Initssratt();
	//????
	if (strlen(pin)>0)
	{
		user=SSR_SearchPIN2(Handle, h->UserBuffer, h->UserSize, pin);
		Calcssruseratt(user->PIN,d1, d2);
	}
	else
	{
		if(NULL==h)	return Z_ERROR_NOT_INIT;
		if(h->UserSize==0 || h->UserBuffer==NULL)
		{
			if(Z_ReadUserInfo(Handle)!=Z_ERROR_OK) return Z_ERROR_IO;
		}
		if(h->UserSize==0 || h->UserBuffer==NULL) return Z_ERROR_NO_DATA;
		while(h->cUserBuffer<h->UserBuffer+h->UserSize)
		{		
			u=(SSR_PUser)(h->cUserBuffer);
			h->cUserBuffer=(char*)(u+1); 
			Calcssruseratt(u->PIN,d1,d2);
		}
	}
	//??????��?
	//???????
	SDKattrule=(char*)udk_malloc(sizeof(TAttRules));
	ReadAttRule((pAttRules)SDKattrule);
	switch(HTMLFlag)
	{
		//???????
	case 1:
		{
			OpenHtmFd(FCT_LOGHTM,OutFileName);
			OutputAttLogRep2(RepName,d1,d2);
		}
		break;
		//OutAttAbnorhtm ??????
	case 2:
		{
			OpenHtmFd(FCT_ABNORHTM,OutFileName);
			OutAttAbnorhtm((pAttRules)SDKattrule,d1,d2);
		}
		break;
		//??????
	case 3:
		{
			OpenHtmFd(FCT_CALCUHTM,OutFileName);
			OutAttStathtm((pAttRules)SDKattrule,d1,d2);
		}
		break;
	default:
		printf("maybe I finish it");
	}
	//?????????��?
	SSRfree();
	//udk_free(gssrlogbuffer);
	return TRUE;
}

 int UDK_API Z_GetSysOption(UDK_HANDLE Handle, char *Option, char *Value)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_OPTIONS_RRQ;
	char option[1024]={0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	strcpy(option, Option);
	ZEMBPRO_SENDCMD(h->emh, &cmd, option, sizeof(option), strlen(Option)+1, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	strcpy(Value, option+strlen(Option)+1);
	return Z_ERROR_OK;
}

 int UDK_API Z_ReadRTLog(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_RTLOG_RRQ;
	int ret, bufsize=0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(strcmp(h->version,VER601)<0)
	{
		return Z_ERROR_UNSUPPORT;
	}
	/* dsl 2008.7.24
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
	//h->BufferLen=2048;
	h->BufferLen=2*1024*1024*3;//dsl 2008.7.23
	h->Buffer=(char*)udk_malloc(h->BufferLen);
	//dsl 2008.7.22
	if (!h->Buffer)
	{
	return Z_ERROR_MEMORY;
	}
	}
	//dsl 2007.9.24
	memset((void*)h->Buffer, 0, h->BufferLen);
	*(int*)h->Buffer=h->RTLogNum;
	ret=ZEMBPRO_SENDCMD(h->emh, &cmd, h->Buffer, 1024, 4, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	h->TmpSize=0;
	h->TmpBuffer=NULL; 
	h->cTmpBuffer=NULL; 
	h->UDataSize=0;
	h->UDataBuffer=NULL;
	h->cUDataBuffer=NULL; 
	h->cOLogBuffer=NULL;
	h->OLogBuffer=NULL;
	h->OLogSize=0;
	h->ALogSize=*(int*)(h->Buffer);
	h->ALogBuffer=h->Buffer+4;
	h->cALogBuffer=h->ALogBuffer;
	if(h->ALogSize>0)
	h->RTLogNum++;
	*/
	bufsize = 2048;
	if (h->ReadRTLogBuf)
	{
		memset((void*)h->ReadRTLogBuf, 0, bufsize);
	}
	else
	{

		h->ReadRTLogBuf = (char*)udk_malloc(bufsize);
		if (!h->ReadRTLogBuf)
		{
			return Z_ERROR_MEMORY;
		}
		memset((void*)h->ReadRTLogBuf, 0, bufsize);
	}	

	*(int*)h->ReadRTLogBuf=h->RTLogNum;

	ret=ZEMBPRO_SENDCMD(h->emh, &cmd, h->ReadRTLogBuf, 1024, 4, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}

	h->GetRTLogStartAddr=h->ReadRTLogBuf + 4;
	h->GetRTLogLoopAddr=h->GetRTLogStartAddr;

	h->RTLogSize=*(int*)(h->ReadRTLogBuf);
	if(h->RTLogSize > 0)
	{
		h->RTLogNum++;
	}
	return Z_ERROR_OK;
}

/* int UDK_API Z_GetRTLog((UDK_HANDLE Handle,int EventType, int *PIN, 
int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second,int IsInvalid,char *VerifyMode, char *State);*/
 int UDK_API Z_GetRTLog(UDK_HANDLE Handle,int *EventType, char *Data)
{
	PEmHandle h = (PEmHandle )Handle;
	TRTLog rtlog;
	TNewRTLog newRTLog;
	TTFTRTLog tftRTLog;

	int len;
	//TTime t;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//dsl 2008.7.24
	//if(h->ALogSize==0 || h->ALogBuffer==NULL || h->cALogBuffer==NULL) return Z_ERROR_NO_DATA;
	if (h->RTLogSize == 0 || !h->GetRTLogLoopAddr || !h->GetRTLogStartAddr)
	{
		return Z_ERROR_NO_DATA;
	}

	//if(h->cALogBuffer<h->ALogBuffer+h->ALogSize)
	if(h->GetRTLogLoopAddr < h->GetRTLogStartAddr + h->RTLogSize)
	{
		if (h->IsTFTMachine)
		{
			//dsl 2007.10.9
			len = sizeof(TTFTRTLog);
			//memcpy(&tftRTLog, h->cALogBuffer, len);
			memcpy(&tftRTLog, h->GetRTLogLoopAddr, len);
			*EventType = tftRTLog.EventType;			
			memcpy(Data, tftRTLog.Data, TFTRTLOGSIZE);
			//h->cALogBuffer+=sizeof(TTFTRTLog);
			h->GetRTLogLoopAddr += sizeof(TTFTRTLog);
		}
		else
		{
			//dsl 2007.9.20.
			if (h->IsNewRTStru)
			{
				len = sizeof(TNewRTLog);
				//memcpy(&newRTLog, h->cALogBuffer, len);
				memcpy(&newRTLog, h->GetRTLogLoopAddr, len);
				*EventType = newRTLog.EventType;
				//dsl 2008.1.4
				//memcpy(Data, newRTLog.Data, NEWRTLOGSIZE);
				memcpy(Data, newRTLog.Data, len);
				//h->cALogBuffer+=sizeof(TNewRTLog);
				h->GetRTLogLoopAddr += len;
			}
			else
			{
				len = sizeof(TRTLog);
				//memcpy(&rtlog, h->cALogBuffer, len);
				memcpy(&rtlog, h->GetRTLogLoopAddr, len);
				*EventType = rtlog.EventType;
				//memcpy(Data,rtlog.Data,14);
				memcpy(Data, rtlog.Data, RTLOGSIZE);
				//h->cALogBuffer+=sizeof(TRTLog);
				h->GetRTLogLoopAddr+=len;
			}
		}
	}
	else
	{
		return Z_ERROR_NO_DATA;
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_SetSysOption(UDK_HANDLE Handle, char *ParamName, char *Value)
{
	PEmHandle h = (PEmHandle )Handle;
	char Option[140];
	unsigned short cmd = CMD_OPTIONS_WRQ;
	if (h == NULL)
	{
		return Z_ERROR_NOT_INIT;
	}

	if (strlen(ParamName) == 0)
	{
		return Z_ERROR_PARAM;//??��????????
	}	
	memset(Option, 0, sizeof(Option));
	sprintf(Option,"%s", ParamName);
	if ( (h->DeviceType == 0) && (Option[0] == '~') )
	{	
		char ln[60], v[130], value[50];			
		int i, len=0;

		sprintf(value,"%s",Value);
		len = strlen(value);
		ln[0] = GetUS() & 0xFF;

		for(i=0; i<len; i++)
			ln[i+1] = ln[i]^(value[i]);
		for(i=0; i<len+1; i++)
			sprintf(v+i*2,"%02X",ln[i]);		

		i = strlen(Option);
		sprintf(Option+i,"%s","=");
		sprintf(Option+i+1, "%s", v);		
	}
	else
	{
		sprintf(Option, "%s=%s", ParamName, Value);
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, Option, 0, strlen(Option)+1, h->WaitTimeForACommand);
	if (cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}	
	return Z_ERROR_OK;
}



 int UDK_API Z_SetHoliday(UDK_HANDLE Handle, char *TZ)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[210] = {0};
	unsigned short cmd = CMD_HTZ_WRQ;
	int i, iLen = 0, iCount = 0;
	int TZIndex = HTZID;	
	PHoliday tz = (PHoliday)(buf+4);
	iLen = strlen(TZ);

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	*(int*)buf=TZIndex;

	for(i=0;i<24;i++)
	{
		tz->intervals[i][0][0] = 0;
		tz->intervals[i][0][1] = 0;
		tz->intervals[i][1][0] = 0;
		tz->intervals[i][1][1] = 0;
	}	

	for(i=0;i<24;i++)
	{
		tz->intervals[i][0][0]=(TZ[0]-'0')*10 + (TZ[1]-'0');
		if(tz->intervals[i][0][0] < 0 || tz->intervals[i][0][0] > 12) return Z_ERROR_PARAM;

		tz->intervals[i][0][1]=(TZ[2]-'0')*10 + (TZ[3]-'0');
		if(tz->intervals[i][0][1]<0 || tz->intervals[i][0][1] > 31) return Z_ERROR_PARAM;

		tz->intervals[i][1][0]=(TZ[4]-'0')*10 + (TZ[5]-'0');
		if(tz->intervals[i][1][0]<0 || tz->intervals[i][1][0]> 12) return Z_ERROR_PARAM;

		tz->intervals[i][1][1]=(TZ[6]-'0')*10 + (TZ[7]-'0');
		if(tz->intervals[i][1][1]<0 || tz->intervals[i][1][1]> 31) return Z_ERROR_PARAM;

		TZ+=8;
		iCount+=8;
		if (iCount >= iLen)
		{
			break;
		}
	}
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 4+sizeof(THoliday), h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_GetHoliday(UDK_HANDLE Handle, char *TZ, int *Length)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[210];
	unsigned short cmd = CMD_HTZ_RRQ;
	int TZIndex = HTZID;	
	int i, iLen = 0;

	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	memset(buf, 0, sizeof(buf));
	*(int*)buf = TZIndex;

	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(buf), 4, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}

	//iLen = strlen(buf);//dsl 2008.11.17
	//*Length = iLen * 2;//dsl 2008.11.17
	iLen = 0;//dsl 2008.11.17

	for(i=0; i<24; i++)
	{
		//dsl 2008.11.17
		if (((PHoliday)buf)->intervals[i][0][0]+((PHoliday)buf)->intervals[i][0][1]+
			((PHoliday)buf)->intervals[i][1][0]+((PHoliday)buf)->intervals[i][1][1])
		{
			iLen++;
		}


		sprintf(TZ,"%02d%02d%02d%02d", ((PHoliday)buf)->intervals[i][0][0],((PHoliday)buf)->intervals[i][0][1],
			((PHoliday)buf)->intervals[i][1][0],((PHoliday)buf)->intervals[i][1][1]);

		TZ+=8;
	}

	*Length = iLen*8;//dsl 2008.11.17

	return Z_ERROR_OK;
}

 int UDK_API Z_GetlockComb(UDK_HANDLE Handle, int CombNo, int *Group1, int *Group2, int *Group3, int *Group4, int *Group5)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};
	PUnlockComb comb = (TUnlockComb *)buf;
	unsigned short cmd = CMD_ULG_RRQ;	

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if (CombNo < 0 || CombNo >  MAXCOMBNO)
	{
		return Z_ERROR_PARAM;
	}

	comb->ID = CombNo;
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)comb, sizeof(TUnlockComb), sizeof(TUnlockComb), h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		if (cmd == CMD_ACK_ERROR)
		{
			return Z_ERROR_DATA_NOEXISTED;
		}
		return Z_ERROR_IO;
	}

	*Group1 = comb->GroupID[0];
	*Group2 = comb->GroupID[1];
	*Group3 = comb->GroupID[2];
	*Group4 = comb->GroupID[3];
	*Group5 = comb->GroupID[4];	
	return Z_ERROR_OK;
}
 int UDK_API Z_SetlockComb(UDK_HANDLE Handle, int CombNo, int Group1, int Group2, int Group3, int Group4, int Group5)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};
	int i = 0, j = 0;
	unsigned short cmd=CMD_ULG_WRQ;	
	PUnlockComb comb=(PUnlockComb)buf;

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if ((CombNo > MAXCOMBNO || Group1 > MAXGROUPNO || Group2 > MAXGROUPNO || Group3 > MAXGROUPNO || Group4 > MAXGROUPNO || Group5 > MAXGROUPNO)
		&& (CombNo < 0 || Group2 < 0 || Group3 < 0 || Group4 < 0 || Group5 < 0))
	{
		return Z_ERROR_PARAM;
	}

	if (Group1 > 0)	j++;
	if (Group2 > 0)	j++;
	if (Group3 > 0)	j++;
	if (Group4 > 0)	j++;
	if (Group5 > 0)	j++;	

	comb->ID = CombNo;
	comb->GroupID[0] = Group1;
	comb->GroupID[1] = Group2;
	comb->GroupID[2] = Group3;
	comb->GroupID[3] = Group4;
	comb->GroupID[4] = Group5;
	comb->MemberCount = j;

	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, sizeof(TUnlockComb), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
 int UDK_API Z_GetGroupTZ(UDK_HANDLE Handle, int GroupNo, int *tz1, int *tz2, int *tz3, int *VaildHoliday, int *VerifyStyle)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};
	int vs = 0,  iHoliday = 0;
	PGroup group = (TGroup *)buf;
	unsigned short cmd = CMD_GRPTZ_RRQ;	

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if (GroupNo < 0 || GroupNo >  MAXGROUPNO)
	{
		return Z_ERROR_PARAM;
	}

	group->ID = GroupNo;
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)group, sizeof(TGroup), sizeof(TGroup), h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		if (cmd == CMD_ACK_ERROR)
		{
			return Z_ERROR_DATA_NOEXISTED;
		}
		return Z_ERROR_IO;
	}

	*tz1 = group->TZID[0];
	*tz2 = group->TZID[1];
	*tz3 = group->TZID[2];
	if (group->VerifyStyle & 0x80)
	{
		iHoliday = 1;
	}
	*VaildHoliday = iHoliday;
	*VerifyStyle = (group->VerifyStyle & 0x7F);//+1;//yuping, ???+1

	return Z_ERROR_OK;
}

 int UDK_API Z_SetGroupTZ(UDK_HANDLE Handle, int GroupNo, int tz1, int tz2, int tz3, int VaildHoliday, int VerifyStyle)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};
	int vs = 0;
	unsigned short cmd=CMD_GRPTZ_WRQ;	
	PGroup group=(PGroup)buf;

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if ((GroupNo > MAXGROUPNO || tz1 > MAXTZNO || tz2 > MAXTZNO || tz3 > MAXTZNO) && (GroupNo < 1))		
	{
		return Z_ERROR_PARAM;
	}

	//(0-14)
	vs = VerifyStyle;// - 1;
	if (VaildHoliday != 0)
	{
		vs |= 0x80;
	}

	group->ID = GroupNo;
	group->TZID[0] = tz1;
	group->TZID[1] = tz2;
	group->TZID[2] = tz3;
	group->VerifyStyle = vs & 0xFF;


	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, sizeof(TGroup), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetHolidayTZ(UDK_HANDLE Handle, int ID, int *Month1, int *Day1, int *Month2, int *Day2, int *TZID)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};
	PHolidayTz Holiday=(PHolidayTz)buf;
	unsigned short cmd = CMD_SSRHTZ_RRQ;	

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if (ID < 1 || ID >  MINHOLIDAYNO)
	{
		return Z_ERROR_PARAM;
	}

	Holiday->ID = ID;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(THolidayTz), sizeof(THolidayTz), h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		if (cmd == CMD_ACK_ERROR)
		{
			return Z_ERROR_DATA_NOEXISTED;
		}
		return Z_ERROR_IO;
	}

	*TZID = Holiday->TZID;
	*Month1 = Holiday->HDate[HTZ_START][HTZ_MONTH];
	*Day1 = Holiday->HDate[HTZ_START][HTZ_DAY];
	*Month2 = Holiday->HDate[HTZ_END][HTZ_MONTH];
	*Day2 = Holiday->HDate[HTZ_END][HTZ_DAY];
	return Z_ERROR_OK;
}

 int UDK_API Z_SetHolidayTZ(UDK_HANDLE Handle, int ID, int Month1, int Day1, int Month2, int Day2, int TZID)
{
	PEmHandle h = (PEmHandle )Handle;
	char buf[10] = {0};	
	unsigned short cmd = CMD_SSRHTZ_WRQ;	

	PHolidayTz Holiday=(PHolidayTz)buf;

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if (ID > MINHOLIDAYNO || Month1 > 12 || Month2 > 12 || Day1 > 31 || Day2 > 31 || ID < 1 )		
	{
		return Z_ERROR_PARAM;
	}

	Holiday->ID = ID;
	Holiday->TZID = TZID;
	Holiday->HDate[HTZ_START][HTZ_MONTH] = Month1;
	Holiday->HDate[HTZ_START][HTZ_DAY] = Day1;
	Holiday->HDate[HTZ_END][HTZ_MONTH] = Month2;
	Holiday->HDate[HTZ_END][HTZ_DAY] = Day2;

	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, sizeof(THolidayTz), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SetSsrUData(UDK_HANDLE Handle, char *EnrollNum, int SmsID)
{	
	PEmHandle h = (PEmHandle )Handle;
	TUData ud;
	int pin;
	unsigned short cmd=CMD_UDATA_WRQ;	
	SSR_PUser pUser = NULL;

	if(NULL == h)	
	{
		return Z_ERROR_NOT_INIT;
	}
	memset((void*)&ud, 0, sizeof(TUData));

	if(h->UserBuffer==NULL||h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	pUser = SSR_SearchPIN2(Handle, h->UserBuffer, h->UserSize, EnrollNum);

	if (!pUser)
	{
		return Z_ERROR_NO_DATA;
	}

	ud.PIN = pUser->PIN;
	ud.SMSID = SmsID;	
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&ud, sizeof(TUData), sizeof(TUData), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_DelSsrUData(UDK_HANDLE Handle, char *EnrollNum, int SmsID)
{
	PEmHandle h = (PEmHandle )Handle;
	TUData ud;
	SSR_PUser pUser = NULL;
	int i = 0;

	unsigned short cmd=CMD_DELETE_UDATA;
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}
	memset((void*)&ud,0,sizeof(TUData));

	if(h->UserBuffer==NULL || h->UserBufferLen==0)
	{
		Z_ReadUserInfo(Handle);
	}
	pUser = SSR_SearchPIN2(Handle, h->UserBuffer, h->UserSize, EnrollNum);
	if (!pUser)
	{
		return Z_ERROR_NO_DATA;
	}

	ud.SMSID=SmsID;
	ud.PIN = pUser->PIN;	
	i = ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&ud, 0,sizeof(TUData),  4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2)
	{
		return Z_ERROR_NO_DATA;
	}
	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_IsTFTMachine(UDK_HANDLE Handle, int *Value)
{
	PEmHandle h = (PEmHandle )Handle;
	*Value = 0;
	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if (h->IsTFTMachine)
	{
		*Value = 1;
	}
	return Z_ERROR_OK;
}

 int Z_SendBackgroundCMD(UDK_HANDLE Handle, int command, int param1, int param2, int param3)
{
	int buf[40] = {0};
	UDK_U16 cmd = command;
	PEmHandle h = (PEmHandle )Handle;

	buf[0] = param1;
	buf[1] = param2;
	buf[2] = param3;


	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)buf, sizeof(buf), 12, h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

 int UDK_API Z_SendFile(UDK_HANDLE Handle, char *FileName)
{
	PEmHandle h = (PEmHandle)Handle; 
	unsigned short cmd = CMD_UPDATE_FIRMWARE;
	char cmdBuf[40] = {0};
	FILE *fp = NULL;
	int SendLen = 0;
	char *buffer = NULL;
	size_t retsize;

	if(FileName == NULL)
	{
		return Z_ERROR_PARAM;
	}
	if(NULL == h)	
	{
		return Z_ERROR_NOT_INIT;
	}	

	//????????,??????????????	
	*((int*)cmdBuf) = CMD_UPDATEFILE;	
	if(strrchr(FileName, '\\') == NULL)
	{
		strcpy(cmdBuf+4,FileName);
	}
	else
	{
		strcpy(cmdBuf+4, strrchr(FileName, '\\') + 1);
	}	

	//??????????????????????
	fp = fopen(FileName, "rb");
	if(fp == NULL)
	{
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_IO;
	}
	fseek(fp, 0, SEEK_END);
	SendLen = ftell(fp);	
	fseek(fp, 0, SEEK_SET);

	if(SendLen<CUSTFILESIZE)
	{
		buffer = (char *)udk_malloc(CUSTFILESIZE);
	}
	else
	{
		buffer = (char *)udk_malloc(SendLen);
	}

	if(buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(buffer, 0, SendLen);


	retsize=fread(buffer, SendLen, 1, fp);

	Z_DisableDevice(Handle, 3);

	ZEMBPRO_SENDCMDDATA(h->emh, &cmd, buffer, SendLen, cmdBuf, strlen(FileName) + 4 + 1, 4*h->WaitTimeForACommand);
	Z_EnableDevice(Handle);

	fclose(fp);
	udk_free(buffer);
	buffer = NULL;

	if(cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	else
	{
		return Z_ERROR_OK;
	}
}
 int UDK_API Z_SendLogoFile(UDK_HANDLE Handle, char *FileName)
{
	PEmHandle h = (PEmHandle )Handle; 
	unsigned short cmd = CMD_UPDATE_FIRMWARE;
	char cmdBuf[40] = {0};
	FILE *fp = NULL;
	int SendLen = 0;
	char *buffer = NULL;
	ssize_t retsize;

	if(FileName == NULL)
	{
		return Z_ERROR_PARAM;
	}
	if(NULL == h)	
	{
		return Z_ERROR_NOT_INIT;
	}	

	//????????,??????????????	
	*((int*)cmdBuf) = UPDATE_FLASH;	
	if(strrchr(FileName, '\\') == NULL)
	{
		strcpy(cmdBuf+4,FileName);
	}
	else
	{
		strcpy(cmdBuf+4, strrchr(FileName, '\\') + 1);
	}	

	buffer = (char *)udk_malloc(CUSTFILESIZE);
	if(buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(buffer, 0, CUSTFILESIZE);

	//??????????????????????
	fp = fopen(FileName, "rb");
	if(fp == NULL)
	{
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_IO;
	}
	fseek(fp, 0, SEEK_END);
	SendLen = ftell(fp);	
	fseek(fp, 0, SEEK_SET);
	retsize=fread(buffer, SendLen, 1, fp);

	Z_DisableDevice(Handle, 3);

	ZEMBPRO_SENDCMDDATA(h->emh, &cmd, buffer, SendLen, cmdBuf, strlen(FileName) + 4 + 1, 4*h->WaitTimeForACommand);
	Z_EnableDevice(Handle);

	fclose(fp);
	udk_free(buffer);
	buffer = NULL;

	if(cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	else
	{
		return Z_ERROR_OK;
	}
}

 int UDK_API Z_UpdateLanguageByID(UDK_HANDLE Handle, int LanguageID, char *FileName)
{
	PEmHandle h = (PEmHandle )Handle;
	char value[100] = {0};
	unsigned short cmd = CMD_UPDATEFILEBYID; 
	if (LanguageID < 0 || FileName == NULL)
	{
		return Z_ERROR_PARAM;
	}
	*((int*)value) = LanguageID;
	memcpy(value+4, FileName, strlen(FileName));
	Z_DisableDevice(Handle, 3);
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)value, sizeof(value), sizeof(value), h->WaitTimeForACommand);
	Z_EnableDevice(Handle);
	if(cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	else
	{
		return Z_ERROR_OK;
	}


}

 int UDK_API Z_ReadFile(UDK_HANDLE Handle, char *FileName, char *FilePath)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_READFILE;
	int size = 0;

	char *temp_Buf = NULL;
	int bufSize = MAXSIZE;

	if(NULL == h)	return Z_ERROR_NOT_INIT;
	//?????????????
	temp_Buf = (char *)udk_malloc(bufSize);
	if(temp_Buf == NULL) return Z_ERROR_NO_SPACE;
	memset(temp_Buf, 0, bufSize);
	strcpy(temp_Buf, FileName);

	size = ZEMBPRO_READDATA(h->emh,&cmd,temp_Buf, bufSize, strlen(FileName) + 1, h->BlockSize, 2000 + h->WaitTimeFor1KData);	
	if(cmd == CMD_ACK_OK)
	{
		//??????????????????????,??????????????��??
		char path[200] = {0};
		FILE *fp = NULL;
		//GetModuleFileName(NULL,path,199);    //----------------------------::????

		//*strrchr(path, '\\') = '\0';
		//strcat(path,"\\");
		//strcat(path, FileName);
		sprintf(path,"%s%s", FilePath, FileName);

		fp = fopen(path, "wb");
		if(fp == NULL)
		{
			udk_free(temp_Buf);
			temp_Buf = NULL;
			return Z_ERROR_IO;
		}
		fwrite(temp_Buf, 1, size, fp);

		fclose(fp);
		udk_free(temp_Buf);
		temp_Buf = NULL;
		return Z_ERROR_OK;
	}
	else
	{
		udk_free(temp_Buf);
		temp_Buf = NULL;
		return Z_ERROR_IO;
	}
}

 int UDK_API Z_ReadLogEx(UDK_HANDLE Handle, int NewLog, int LastCount)
{
	PEmHandle h = (PEmHandle )Handle;
	h->LastCount = LastCount;
	return Z_ReadLog(h, NewLog);
}

 int UDK_API Z_SetCustomizeAttState(UDK_HANDLE Handle, int OldState, int NewState)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_CUSTATTSTATE_WRQ;
	TCustState State;

	if(NULL==h)	return Z_ERROR_NOT_INIT;

	if (OldState > 7 || OldState < 0 || !h->ExtendFmt)
	{
		return Z_ERROR_PARAM;
	}

	if (h->ExtendFmt && (NewState > 127 || NewState < 0) )
	{		
		return Z_ERROR_PARAM;		
	}

	memset((void*)&State,0,sizeof(TCustState));
	State.Identity = (short)OldState;
	State.CustState= (short)NewState;
	State.UseCustState = 1;	
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&State, sizeof(TCustState), sizeof(TCustState), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_DelCustomizeAttState(UDK_HANDLE Handle, int OldState)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_DELCUSTATTSTATE;
	char buf[4] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (OldState > 7 || OldState < 0 || !h->ExtendFmt)
	{
		return Z_ERROR_PARAM;
	}	

	*((UDK_U16*)buf) = OldState;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(buf), sizeof(buf), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_EnableCustomizeAttState(UDK_HANDLE Handle, int OldState, int Enable)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_USECUSTATTSTATE;
	short i = 0;
	char buf[6] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (OldState > 7 || OldState < 0 || !h->ExtendFmt)
	{
		return Z_ERROR_PARAM;
	}	
	if (Enable)
	{
		i = 1;
	}
	*((UDK_U16*)buf) = OldState;
	*((UDK_U16*)buf+1) = i;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(buf), sizeof(buf), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//customize voice
 int UDK_API Z_SetCustomizeVoice(UDK_HANDLE Handle, int VoiceID, char *FileName)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_CUSTVOICE_WRQ;
	TCustVoice cust;

	if(NULL==h)	return Z_ERROR_NOT_INIT;

	if (VoiceID > 20 || VoiceID < 0 || (0 ==strlen(FileName)) || strchr(FileName, '\\') || !strcmp(FileName, "beep.wav"))
	{
		return Z_ERROR_PARAM;
	}

	memset((void*)&cust,0,sizeof(TCustVoice));
	*((UDK_U16*)cust.Identity) = VoiceID;
	memset(cust.Name, 0, sizeof(cust.Name));
	sprintf(cust.Name, "%s", FileName);	
	cust.UseCustVoice = 1;	
	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&cust, sizeof(TCustVoice), sizeof(TCustVoice), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_DelCustomizeVoice(UDK_HANDLE Handle, int VoiceID)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_DELCUSTVOICE;
	char buf[4] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (VoiceID > 20 || VoiceID < 0 )
	{
		return Z_ERROR_PARAM;
	}

	*((UDK_U16*)buf) = VoiceID;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(buf), sizeof(buf), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_EnableCustomizeVoice(UDK_HANDLE Handle, int VoiceID, int Enable)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_USECUSTVOICE;
	short i = 0;
	char buf[6] = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if (VoiceID > 20 || VoiceID < 0 )
	{
		return Z_ERROR_PARAM;
	}	
	if (Enable)
	{
		i = 1;
	}
	*((UDK_U16*)buf) = VoiceID;
	*((UDK_U16*)buf+1) = i;
	ZEMBPRO_SENDCMD(h->emh, &cmd, buf, sizeof(buf), sizeof(buf), h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//???�z?zhc??2010-04-26???????????????��?????? ???????
 int UDK_API Z_StartEnrollEx(UDK_HANDLE Handle, char *UserID, int FingerID,int Flag)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_STARTENROLL;
	char Buffer[30] = {0};
	int res = 0; 
	int UserNoLen = 24;
	int sendlen = 0;

	if(NULL==h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if (h->IsTFTMachine)
	{
		strcpy(Buffer, UserID);
		Buffer[24] = FingerID;
		Buffer[25] = Flag;

		sendlen = UserNoLen+1+1;		
	}
	else
	{
		if(h->PINWidth <= 5)
		{
			*(WORD*)Buffer = atol(UserID);
			Buffer[2] = FingerID;			
			Buffer[3] = Flag;
			sendlen = 2 + 1 + 1;
		}
		else
		{
			*(int*)Buffer = atol(UserID);
			Buffer[4] = FingerID;
			Buffer[5] = Flag;
			sendlen = 4 + 1 + 1;

			//9��??????????1,?????????��?????????????????????pin2?pin???????????��??????????????2010.09.16
			gIsEnroll = 1;
		}		
	}

	res=ZEMBPRO_SENDCMD(h->emh, &cmd, Buffer, 30, sendlen, h->WaitTimeForACommand);

	if(cmd!=CMD_ACK_OK)
	{
		return res;
	}

	return Z_ERROR_OK;
}

//yuping, jlf->zhuliu
 int UDK_API SSR_Z_SetUserTmpExt(UDK_HANDLE Handle, int IsDeleted, char *PIN, int FingerIndex, char *TmpData)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_SSRUSERTEMP_WRQ;
	char buf[2048];
	int i,Size;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memset(buf,0,2048);
	Size=TestTemplate41((UDK_U8*)TmpData, (UDK_U8*)(buf+28));
	if(Size>1024-(8+5))
	{
		Size=SetBiokeyTemplateLen((UDK_U8*)TmpData, 1024-(8+5));
		if(Size==0)
			return Z_ERROR_SIZE;
	}
	if(Size<50) return Z_ERROR_SIZE;
	//WORD*)buf=SSR_GetPIN1(h, PIN);

	memcpy(buf,PIN,24);                             //worker id
	buf[24]=(char)IsDeleted;					//22+1+1
	buf[25]=(char)FingerIndex;						//22+1+2
	*(UDK_U16*)(buf+26)=Size;							//22+1+3
	if(h->IsBatchUpdate){
		if(h->IsForceUpdate)
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=2;
		else
			(h->TmpOpBuf+h->TmpOpBufLen)[0]=1;//???????
		//*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf; //UserID
		memcpy(h->TmpOpBuf+h->TmpOpBufLen+1,buf,24);  //UserID 

		(h->TmpOpBuf+h->TmpOpBufLen)[26]=(char)FingerIndex;	//FingerID
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+27)=h->TmpsBufLen;//Offset
		h->TmpOpBufLen+=(22+8);                      //???? 22+2

		*(UDK_U16*)(h->TmpsBuf+h->TmpsBufLen)=Size;	//??�??
		memcpy(h->TmpsBuf+h->TmpsBufLen+2,buf+28,Size);//??? 22+1+6
		h->TmpsBufLen+=Size+2;								//??????????
		return Z_ERROR_OK;
	}

	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, Size+28, 1000+h->WaitTimeForACommand);
	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

//????????????				24��PIN added by ycy 2008-01-11
 int UDK_API SSR_Z_DelUserExt(UDK_HANDLE Handle, char* PIN)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_SSRDELETE_USER;
	int i;
	UDK_U16 PIN1;
	SSR_PUser user=(SSR_PUser)udk_malloc(sizeof(SSR_TUser));
	if(!h||!user)return Z_ERROR_NOT_INIT;
	//PIN1=SSR_GetPIN1(h, PIN);
	//memcpy(buf,PIN,24);
	if(h->IsBatchUpdate){
		//user->PIN2=PIN;
		memcpy(user->PIN2,PIN,24);
		(h->UserInfoOpBuf+h->UserInfoOpBufLen)[0]=0;	//???????
		memcpy(h->UserInfoOpBuf+h->UserInfoOpBufLen+1,user,sizeof(SSR_TUser));//??????
		h->UserInfoOpBufLen+=sizeof(SSR_PUser)+1;

		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		//*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=PIN;	//???ID
		memcpy(h->TmpOpBuf+h->TmpOpBufLen+1,PIN,24);
		(h->TmpOpBuf+h->TmpOpBufLen)[25]=0xFF;					//FingerID   3+22
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+26)=-1;	//Offset				4+22
		h->TmpOpBufLen+=30;					//22+8
		return Z_ERROR_OK;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, PIN, 0, 24, 2000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?????????????�^PIN???��????????��
//???????????????0???????????1???????????   added by ycy 2008-01-11
 int UDK_API SSR_Z_DelUserTmpExt(UDK_HANDLE Handle, char* PIN, int FingerIndex)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_SSRDELETE_USERTEMP;
	char buf[28];				//6+22
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//*(WORD*)buf=SSR_GetPIN1(h, PIN);
	memcpy(buf,PIN,24);      //24��PIN
	buf[24]=(char)FingerIndex;      // 2+22
	if(h->IsBatchUpdate){
		(h->TmpOpBuf+h->TmpOpBufLen)[0]=0;						//???????
		//*(UDK_U16*)(h->TmpOpBuf+h->TmpOpBufLen+1)=*(WORD*)buf;	//???ID  
		memcpy(h->TmpOpBuf+h->TmpOpBufLen+1,PIN,24);
		(h->TmpOpBuf+h->TmpOpBufLen)[25]=(char)FingerIndex;		//FingerID  3+22
		*(UDK_U32*)(h->TmpOpBuf+h->TmpOpBufLen+26)=-1;	//Offset				4+22
		h->TmpOpBufLen+=30;							//						8+22
		return Z_ERROR_OK;
	}
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 25, 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;

	return Z_ERROR_OK;
}

 int UDK_API Z_SSR_GetWorkCode(UDK_HANDLE Handle,int AWorkCode, char Name[])
{
	PEmHandle h = (PEmHandle )Handle;
	char WorkCodeBuffer[sizeof(TWORKCODE_TFT)+2] = "";
	PWorkCode_TFT PtrMineWordCode;
	char temp_Code[MAX_WORKCODE_LEN + 1];

	unsigned short cmd = CMD_WorkCode_RRQ;

	if(NULL == h)	return Z_ERROR_NOT_INIT;

	WorkCodeBuffer[0] = 0;
	sprintf(WorkCodeBuffer + 1, "%d", AWorkCode);
	ZEMBPRO_SENDCMD(h->emh, &cmd, WorkCodeBuffer, sizeof(WorkCodeBuffer)+2, 10, h->WaitTimeForACommand);
	if(cmd != CMD_ACK_OK) return Z_ERROR_IO;
	PtrMineWordCode = (PWorkCode_TFT)WorkCodeBuffer;

	memcpy(Name, PtrMineWordCode->Name, MAX_WORKCODE_NAME_LEN);
	Name[MAX_WORKCODE_NAME_LEN] = '\0';

	return Z_ERROR_OK;
}

 int UDK_API Z_SSR_SetWorkCode(UDK_HANDLE Handle, int AWorkCode, char Name[])
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd=CMD_WorkCode_WRQ;
	TWORKCODE_TFT MineWorkCode;
	char temp_Code[MAX_WORKCODE_LEN + 2];

	if(NULL==h)	return Z_ERROR_NOT_INIT;

	memset((void*)&MineWorkCode,0,sizeof(TWORKCODE_TFT));
	MineWorkCode.PIN = 0; //??PIN??0
	sprintf(temp_Code, "%d", AWorkCode);
	memcpy(MineWorkCode.Code, temp_Code, MAX_WORKCODE_LEN);
	memcpy(MineWorkCode.Name, Name, MAX_WORKCODE_NAME_LEN);

	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)&MineWorkCode, sizeof(MineWorkCode), sizeof(MineWorkCode), h->WaitTimeForACommand);
	if(cmd != CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SSR_DeleteWorkCode(UDK_HANDLE Handle, int AWorkCode)
{
	PEmHandle h = (PEmHandle )Handle;  
	unsigned short cmd = CMD_DELETE_WorkCode;
	char temp_Code[MAX_WORKCODE_LEN + 1] = "";
	int result = 0;

	if(NULL == h)	return Z_ERROR_NOT_INIT;
	sprintf(temp_Code, "%ld", (long)AWorkCode);
	result = ZEMBPRO_SENDCMD(h->emh, &cmd, temp_Code, 0, MAX_WORKCODE_LEN, 4000+h->WaitTimeForACommand);
	if(cmd == CMD_ACK_ERROR && result == 2) return Z_ERROR_NO_DATA;
	if(cmd != CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

 int UDK_API Z_SSR_ClearWorkCode(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_CLEAR_DATA;
	char fct_id;
	if(NULL == h)	return Z_ERROR_NOT_INIT;
	//CMD_Clear_WordCode;
	fct_id = 17;
	ZEMBPRO_SENDCMD(h->emh, &cmd, &fct_id, 1, 1, 3000+h->WaitTimeForACommand);
	if(cmd != CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}
//***********---------   add  end    ----------*******************************

//add by yuping, tft oplog bug
//ssr????????
#pragma pack(push)
#pragma pack(1)
typedef struct _SSR_OPLog_{
	char Admin[24];         //24  	?????????
	UDK_U8 OP;                //1	????????
	UDK_U32 time_second;     //4	???????
	UDK_U16 Users[3];           //2*3	???????
	char User[24];          //24	???????
	UDK_U8 Reserver;          //1    ????��
}SSR_TOPLog, *SSR_POPLog;
#pragma pack(pop)

//
 int UDK_API Z_SSR_GetOpLog(UDK_HANDLE Handle,char *AdminPin, char *UserPin, int *OPStyle, char *OPTime, int *Params)
{
	PEmHandle h = (PEmHandle )Handle;
	//SSR_TOPLog log;

	int len;
	TTime t;
	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(h->OLogSize == 0 || h->Buffer == NULL)
	{
		//??��??????????????????
		if(Z_ReadOpLog(Handle, TRUE) != Z_ERROR_OK)
		{
			return Z_ERROR_IO;
		}
	}
	if(h->OLogSize==0 || h->OLogBuffer==NULL)
	{
		return Z_ERROR_NO_DATA;
	}

	if(h->cOLogBuffer < (h->OLogBuffer + h->OLogSize))
	{
		SSR_TOPLog *pOpLog = (SSR_TOPLog *)h->cOLogBuffer;
		h->cOLogBuffer += sizeof(SSR_TOPLog);
		if(h->cOLogBuffer > h->Buffer + h->BufferLen)
		{
			return Z_ERROR_NO_DATA;
		}

		memcpy(AdminPin, pOpLog->Admin, 24);
		memcpy(UserPin, pOpLog->User, 24);
		*OPStyle = pOpLog->OP;
		Params[0] = pOpLog->Users[0];
		Params[1] = pOpLog->Users[1];
		Params[2] = pOpLog->Users[2];

		DecodeTime(pOpLog->time_second, &t);
		sprintf(OPTime, "%02d", t.tm_mon);
		strcat(OPTime, "-");
		sprintf(OPTime + strlen(OPTime), "%02d", t.tm_mday);
		strcat(OPTime, "-");
		sprintf(OPTime + strlen(OPTime), "%d", t.tm_year);
		strcat(OPTime, " ");
		sprintf(OPTime + strlen(OPTime), "%02d", t.tm_hour);
		strcat(OPTime, ":");
		sprintf(OPTime + strlen(OPTime), "%02d", t.tm_min);
		//strcat(OPTime, ":");
		//sprintf(OPTime + strlen(OPTime), "%02d", t.tm_sec);

		//*Year = t.tm_year;
		//*Month = t.tm_mon;
		//*Day = t.tm_mday;
		//*Hour = t.tm_hour;
		//*Minute = t.tm_min;
		//*Second = t.tm_sec;
	}	
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}
//end

//??????????????????
//1????????????????????????????????????????????????????????????????????????????
//2?????��?????????statecode????
//3?????��???????????????????��?????????��???????????????????��?????????
UDK_BOOL UDK_API clashCheckOld(POldShortKey shortKeyTable, TOldShortKey setItem, int Num)
{
	int i = 0, j = 0;

	if(setItem.keyFun == 1)//set to stateKey
	{
		for(i = 0; i < Num; ++i)
		{
			//2
			if((setItem.keyID != shortKeyTable->keyID) && (setItem.stateCode == shortKeyTable->stateCode))
			{
				return TRUE;
			}
			//3,key id?????????????????????????��?,??????????��????
			if((setItem.keyID != shortKeyTable->keyID) && (shortKeyTable->keyFun == 1) && (setItem.keyFun == 1) 
				&& setItem.autochange && shortKeyTable->autochange)
			{
				if((setItem.Time1 != 0 && shortKeyTable->Time1 != 0 && setItem.Time1 == shortKeyTable->Time1)
					|| (setItem.Time2 != 0 && shortKeyTable->Time2 != 0 && setItem.Time2 == shortKeyTable->Time2)
					|| (setItem.Time3 != 0 && shortKeyTable->Time3 != 0 && setItem.Time3 == shortKeyTable->Time3)
					|| (setItem.Time4 != 0 && shortKeyTable->Time4 != 0 && setItem.Time4 == shortKeyTable->Time4)
					|| (setItem.Time5 != 0 && shortKeyTable->Time5 != 0 && setItem.Time5 == shortKeyTable->Time5)
					|| (setItem.Time6 != 0 && shortKeyTable->Time6 != 0 && setItem.Time6 == shortKeyTable->Time6)
					|| (setItem.Time7 != 0 && shortKeyTable->Time7 != 0 && setItem.Time7 == shortKeyTable->Time7))
				{
					return TRUE;
				}
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else if(setItem.keyFun == 2)
	{
		for(i = 0; i < Num; ++i)
		{
			if((shortKeyTable->keyFun == 2) && (setItem.keyID != shortKeyTable->keyID))
			{
				return TRUE;
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else if(setItem.keyFun == 3)
	{
		for(i = 0; i < Num; ++i)
		{
			if((shortKeyTable->keyFun == 3) && (setItem.keyID != shortKeyTable->keyID))
			{
				return TRUE;
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else//set to undefine
	{
		return FALSE;
	}
}

//??????????????????
//1????????????????????????????????????????????????????????????????????????????
//2?????��?????????statecode????
//3?????��???????????????????��?????????��???????????????????��?????????
UDK_BOOL UDK_API clashCheck(PShortKey shortKeyTable, TShortKey setItem, int Num)
{
	int i = 0, j = 0;

	if(setItem.keyFun == 1)//set to stateKey
	{
		for(i = 0; i < Num; ++i)
		{
			//2
			if((shortKeyTable->keyFun == 1) && (setItem.keyID != shortKeyTable->keyID) && (setItem.stateCode == shortKeyTable->stateCode))
			{
				return TRUE;
			}
			//3,key id?????????????????????????��?,??????????��????
			if((shortKeyTable->keyFun == 1) && (setItem.keyID != shortKeyTable->keyID) && (shortKeyTable->keyFun == 1) && (setItem.keyFun == 1) 
				&& setItem.autochange && shortKeyTable->autochange)
			{
				if((setItem.Time1 != 0 && shortKeyTable->Time1 != 0 && setItem.Time1 == shortKeyTable->Time1)
					|| (setItem.Time2 != 0 && shortKeyTable->Time2 != 0 && setItem.Time2 == shortKeyTable->Time2)
					|| (setItem.Time3 != 0 && shortKeyTable->Time3 != 0 && setItem.Time3 == shortKeyTable->Time3)
					|| (setItem.Time4 != 0 && shortKeyTable->Time4 != 0 && setItem.Time4 == shortKeyTable->Time4)
					|| (setItem.Time5 != 0 && shortKeyTable->Time5 != 0 && setItem.Time5 == shortKeyTable->Time5)
					|| (setItem.Time6 != 0 && shortKeyTable->Time6 != 0 && setItem.Time6 == shortKeyTable->Time6)
					|| (setItem.Time7 != 0 && shortKeyTable->Time7 != 0 && setItem.Time7 == shortKeyTable->Time7))
				{
					return TRUE;
				}
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else if(setItem.keyFun == 2)
	{
		for(i = 0; i < Num; ++i)
		{
			if((shortKeyTable->keyFun == 2) && (setItem.keyID != shortKeyTable->keyID))
			{
				return TRUE;
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else if(setItem.keyFun == 3)
	{
		for(i = 0; i < Num; ++i)
		{
			if((shortKeyTable->keyFun == 3) && (setItem.keyID != shortKeyTable->keyID))
			{
				return TRUE;
			}
			++shortKeyTable;
		}
		return FALSE;
	}
	else//set to undefine
	{
		return FALSE;
	}
}

int Z_SSR_SetOldShortKey(UDK_HANDLE Handle, int ShortKeyID, int ShortKeyFun, int StateCode,
						 char StateName[], int AutoChange, char Time[])
{
	PEmHandle h = (PEmHandle )Handle;
	TOldShortKey SendBuffer = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;

	if(ShortKeyFun == 1)//set to state key
	{
		/*int timeHour[7] = {0};
		int timeMinute[7] = {0};
		int wd = 0;
		char *startPos = Time, *MPos = NULL, *FPos = NULL;
		MPos = strchr(startPos, ":");
		FPos = strchr(startPos, ";");*/
		int time1Hour = 0, time1Minute = 0;
		int time2Hour = 0, time2Minute = 0;
		int time3Hour = 0, time3Minute = 0;
		int time4Hour = 0, time4Minute = 0;
		int time5Hour = 0, time5Minute = 0;
		int time6Hour = 0, time6Minute = 0;
		int time7Hour = 0, time7Minute = 0;

		//Time??????????
		sscanf(Time, "%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;", &time1Hour,&time1Minute, &time2Hour, &time2Minute,
			&time3Hour, &time3Minute, &time4Hour, &time4Minute, &time5Hour, &time5Minute, &time6Hour, &time6Minute, &time7Hour, &time7Minute);
		if(    time1Hour < 0 || time1Hour > 23 || time1Minute < 0 || time1Minute > 59
			|| time2Hour < 0 || time2Hour > 23 || time2Minute < 0 || time2Minute > 59
			|| time3Hour < 0 || time3Hour > 23 || time3Minute < 0 || time3Minute > 59
			|| time4Hour < 0 || time4Hour > 23 || time4Minute < 0 || time4Minute > 59
			|| time5Hour < 0 || time5Hour > 23 || time5Minute < 0 || time5Minute > 59
			|| time6Hour < 0 || time6Hour > 23 || time6Minute < 0 || time6Minute > 59
			|| time7Hour < 0 || time7Hour > 23 || time7Minute < 0 || time7Minute > 59)
		{
			return Z_ERROR_PARAM;//??????
		}
		else
		{
			SendBuffer.keyID = ShortKeyID;
			SendBuffer.keyFun = ShortKeyFun;
			SendBuffer.stateCode = StateCode;
			memcpy(SendBuffer.stateName, StateName, STATE_NAME_LEN + 2);
			SendBuffer.autochange = AutoChange;
			SendBuffer.Time1 = (time1Hour * 100) + time1Minute;
			SendBuffer.Time2 = (time2Hour * 100) + time2Minute;
			SendBuffer.Time3 = (time3Hour * 100) + time3Minute;
			SendBuffer.Time4 = (time4Hour * 100) + time4Minute;
			SendBuffer.Time5 = (time5Hour * 100) + time5Minute;
			SendBuffer.Time6 = (time6Hour * 100) + time6Minute;
			SendBuffer.Time7 = (time7Hour * 100) + time7Minute;
		}
	}
	else//???????????????
	{
		SendBuffer.keyID = ShortKeyID;
		SendBuffer.keyFun = ShortKeyFun;
		SendBuffer.stateCode = -1;
		//??????0
	}

	{//????????
		unsigned short cmd = CMD_ShortKey_RRQ;
		TOldShortKey *shortKey = NULL;
		char *SKBuffer = NULL;
		int Num = 0, size = 0;

		SKBuffer = (char *)udk_malloc(5 * 1024);
		if(SKBuffer == NULL)
		{
			return Z_ERROR_NO_SPACE;
		}
		memset(SKBuffer, 0, 5 * 1024);
		size = ZEMBPRO_READDATA(h->emh, &cmd, SKBuffer, 5 * 1024, 0, h->BlockSize, 1000 + h->WaitTimeFor1KData);
		if(cmd != CMD_ACK_OK)
		{
			udk_free(SKBuffer);
			SKBuffer = NULL;
			return Z_ERROR_IO;
		}
		if((size - sizeof(int)) % sizeof(TOldShortKey) != 0)
		{
			udk_free(SKBuffer);
			SKBuffer = NULL;
			return Z_ERROR_IO;
		}

		Num = (size - sizeof(int)) / sizeof(TOldShortKey);
		shortKey = (POldShortKey)(SKBuffer+4);

		if(clashCheckOld(shortKey, SendBuffer, Num))
		{
			return Z_ERROR_PARAM;
		}

	}

	{//??????
		unsigned short cmd = CMD_ShortKey_WRQ;
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)(&SendBuffer), sizeof(TOldShortKey), sizeof(TOldShortKey), h->WaitTimeForACommand);
		if(cmd != CMD_ACK_OK)
			return Z_ERROR_IO;
		return Z_ERROR_OK;
	}
}

 int UDK_API Z_SSR_SetShortKey(UDK_HANDLE Handle, int ShortKeyID, int ShortKeyFun, int StateCode,
												 char StateName[], int AutoChange, char Time[])
{
	PEmHandle h = (PEmHandle )Handle;
	TShortKey SendBuffer = {0};
	if(NULL==h)	return Z_ERROR_NOT_INIT;

	if(strcmp(h->version,VER660)<0)
	{
		return Z_SSR_SetOldShortKey(Handle,ShortKeyID,ShortKeyFun,StateCode,StateName,AutoChange,Time);
	}

	if(ShortKeyFun == 1)//set to state key
	{
		/*int timeHour[7] = {0};
		int timeMinute[7] = {0};
		int wd = 0;
		char *startPos = Time, *MPos = NULL, *FPos = NULL;
		MPos = strchr(startPos, ":");
		FPos = strchr(startPos, ";");*/
		int time1Hour = 0, time1Minute = 0;
		int time2Hour = 0, time2Minute = 0;
		int time3Hour = 0, time3Minute = 0;
		int time4Hour = 0, time4Minute = 0;
		int time5Hour = 0, time5Minute = 0;
		int time6Hour = 0, time6Minute = 0;
		int time7Hour = 0, time7Minute = 0;

		//Time??????????
		sscanf(Time, "%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;%d:%d;", &time1Hour,&time1Minute, &time2Hour, &time2Minute,
			&time3Hour, &time3Minute, &time4Hour, &time4Minute, &time5Hour, &time5Minute, &time6Hour, &time6Minute, &time7Hour, &time7Minute);
		if(    time1Hour < 0 || time1Hour > 23 || time1Minute < 0 || time1Minute > 59
			|| time2Hour < 0 || time2Hour > 23 || time2Minute < 0 || time2Minute > 59
			|| time3Hour < 0 || time3Hour > 23 || time3Minute < 0 || time3Minute > 59
			|| time4Hour < 0 || time4Hour > 23 || time4Minute < 0 || time4Minute > 59
			|| time5Hour < 0 || time5Hour > 23 || time5Minute < 0 || time5Minute > 59
			|| time6Hour < 0 || time6Hour > 23 || time6Minute < 0 || time6Minute > 59
			|| time7Hour < 0 || time7Hour > 23 || time7Minute < 0 || time7Minute > 59)
		{
			return Z_ERROR_PARAM;//??????
		}
		else
		{
			SendBuffer.keyID = ShortKeyID;
			SendBuffer.keyFun = ShortKeyFun;
			SendBuffer.stateCode = StateCode;
			memcpy(SendBuffer.stateName, StateName, STATE_NAME_LEN + 2);
			SendBuffer.autochange = AutoChange;
			SendBuffer.Time1 = (time1Hour * 100) + time1Minute;
			SendBuffer.Time2 = (time2Hour * 100) + time2Minute;
			SendBuffer.Time3 = (time3Hour * 100) + time3Minute;
			SendBuffer.Time4 = (time4Hour * 100) + time4Minute;
			SendBuffer.Time5 = (time5Hour * 100) + time5Minute;
			SendBuffer.Time6 = (time6Hour * 100) + time6Minute;
			SendBuffer.Time7 = (time7Hour * 100) + time7Minute;
		}
	}
	else//???????????????
	{
		SendBuffer.keyID = ShortKeyID;
		SendBuffer.keyFun = ShortKeyFun;
		SendBuffer.stateCode = -1;
		//??????0
	}

	{//????????
		unsigned short cmd = CMD_ShortKey_RRQ;
		TShortKey *shortKey = NULL;
		char *SKBuffer = NULL;
		int Num = 0, size = 0;

		SKBuffer = (char *)udk_malloc(5 * 1024);
		if(SKBuffer == NULL)
		{
			return Z_ERROR_NO_SPACE;
		}
		memset(SKBuffer, 0, 5 * 1024);
		size = ZEMBPRO_READDATA(h->emh, &cmd, SKBuffer, 5 * 1024, 0, h->BlockSize, 1000 + h->WaitTimeFor1KData);
		if(cmd != CMD_ACK_OK)
		{
			udk_free(SKBuffer);
			SKBuffer = NULL;
			return Z_ERROR_IO;
		}
		if((size - sizeof(int)) % sizeof(TShortKey) != 0)
		{
			udk_free(SKBuffer);
			SKBuffer = NULL;
			return Z_ERROR_IO;
		}

		Num = (size - sizeof(int)) / sizeof(TShortKey);
		shortKey = (PShortKey)(SKBuffer+4);

		if(clashCheck(shortKey, SendBuffer, Num))
		{
			return Z_ERROR_PARAM;
		}

	}

	{//??????
		unsigned short cmd = CMD_ShortKey_WRQ;
		ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)(&SendBuffer), sizeof(TShortKey), sizeof(TShortKey), h->WaitTimeForACommand);
		if(cmd != CMD_ACK_OK)
			return Z_ERROR_IO;
		return Z_ERROR_OK;
	}
}

// int UDK_API Z_SSR_GetStateKey(UDK_HANDLE Handle, int ShortKeyID, /*int *ShortKeyFun,*/ int *StateCode, char StateName[])
int Z_SSR_GetOldShortKey(UDK_HANDLE Handle, int ShortKeyID, int *ShortKeyFun, int *StateCode,
						 char StateName[], int *AutoChange, char Time[])
{
	PEmHandle h = (PEmHandle )Handle;
	int size = 0, Num = 0, i = 0;
	unsigned short cmd = CMD_ShortKey_RRQ;
	TOldShortKey *shortKey = NULL;
	char *Buffer = NULL;
	Buffer = (char *)udk_malloc(5 * 1024);
	if(Buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(Buffer, 0, 5 * 1024);

	if(NULL == h)	return Z_ERROR_NOT_INIT;

	size = ZEMBPRO_READDATA(h->emh, &cmd, Buffer, 5 * 1024, 0, h->BlockSize, 1000 + h->WaitTimeFor1KData);

	if(cmd != CMD_ACK_OK)
	{		
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_IO;
	}
	if((size - sizeof(int)) % sizeof(TOldShortKey) != 0)
	{
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_IO;
	}
	Num = (size - sizeof(int)) / sizeof(TOldShortKey);

	shortKey = (POldShortKey)(Buffer+4);
	for(i = 0; i < Num; ++i)
	{
		if(shortKey->keyID == ShortKeyID)
		{
			*ShortKeyFun = shortKey->keyFun;

			if(shortKey->keyFun == 1)//??????
			{
				*StateCode = shortKey->stateCode;
				memcpy(StateName, shortKey->stateName, STATE_NAME_LEN + 2);
				*AutoChange = shortKey->autochange;

				sprintf(Time, "%02d", (shortKey->Time1 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time1 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time2 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time2 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time3 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time3 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time4 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time4 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time5 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time5 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time6 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time6 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time7 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time7 % 100));
				strcat(Time,";");
			}
			else//??????????.....?????
			{
				*StateCode = 0;
				strcpy(StateName, "");
				*AutoChange = 0;
				strcpy(Time, "");
			}
			break;
		}
		++shortKey;
	}
	if(i == Num)//?????????
	{ 
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_NO_DATA;
	}
	udk_free(Buffer);
	Buffer = NULL;
	return Z_ERROR_OK;
}

// int UDK_API Z_SSR_GetStateKey(UDK_HANDLE Handle, int ShortKeyID, /*int *ShortKeyFun,*/ int *StateCode, char StateName[])
 int UDK_API Z_SSR_GetShortKey(UDK_HANDLE Handle, int ShortKeyID, int *ShortKeyFun, int *StateCode,
												 char StateName[], int *AutoChange, char Time[])
{
	PEmHandle h = (PEmHandle )Handle;
	int size = 0, Num = 0, i = 0;
	unsigned short cmd = CMD_ShortKey_RRQ;
	TShortKey *shortKey = NULL;
	char *Buffer = NULL;
	if(strcmp(h->version,VER660)<0)
	{
		return Z_SSR_GetOldShortKey(Handle,ShortKeyID,ShortKeyFun,StateCode,StateName,AutoChange,Time);
	}

	Buffer = (char *)udk_malloc(5 * 1024);
	if(Buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(Buffer, 0, 5 * 1024);

	if(NULL == h)	return Z_ERROR_NOT_INIT;

	size = ZEMBPRO_READDATA(h->emh, &cmd, Buffer, 5 * 1024, 0, h->BlockSize, 1000 + h->WaitTimeFor1KData);

	if(cmd != CMD_ACK_OK)
	{		
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_IO;
	}
	if((size - sizeof(int)) % sizeof(TShortKey) != 0)
	{
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_IO;
	}
	Num = (size - sizeof(int)) / sizeof(TShortKey);

	shortKey = (PShortKey)(Buffer+4);
	for(i = 0; i < Num; ++i)
	{
		if(shortKey->keyID == ShortKeyID)
		{
			*ShortKeyFun = shortKey->keyFun;

			if(shortKey->keyFun == 1)//??????
			{
				*StateCode = shortKey->stateCode;
				memcpy(StateName, shortKey->stateName, STATE_NAME_LEN + 2);
				*AutoChange = shortKey->autochange;

				sprintf(Time, "%02d", (shortKey->Time1 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time1 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time2 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time2 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time3 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time3 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time4 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time4 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time5 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time5 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time6 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time6 % 100));
				strcat(Time,";");

				sprintf(Time + strlen(Time), "%02d", (shortKey->Time7 / 100));
				strcat(Time,":");
				sprintf(Time + strlen(Time), "%02d", (shortKey->Time7 % 100));
				strcat(Time,";");
			}
			else//??????????.....?????
			{
				*StateCode = 0;
				strcpy(StateName, "");
				*AutoChange = 0;
				strcpy(Time, "");
			}
			break;
		}
		++shortKey;
	}
	if(i == Num)//?????????
	{ 
		udk_free(Buffer);
		Buffer = NULL;
		return Z_ERROR_NO_DATA;
	}
	udk_free(Buffer);
	Buffer = NULL;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetKeyOptions(UDK_HANDLE Handle, char *EmKeyOptions)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL == h)	return Z_ERROR_NOT_INIT;
	memcpy(EmKeyOptions,&(h->EmKeyOptions),sizeof(TEmKeyOptions));
	return Z_ERROR_OK;
}

//-----------------------------------------------------------------------------
//----------------------------FACE---------------------------------------------
//-----------------------------------------------------------------------------

/*FILE* fp;  // ??????????????????????FILE ? stdio.h ?????
fp=fopen(" C:\\a1.txt","w"); //?? fopen ??????????????????????????"w" ???��(write)
if (fp!=NULL) // ?????
fprintf(fp,"%d",cmd);
// fp ???????????"%d"��??????1 ??��??????
fclose(fp);*/

//????????????��????????��??�^
//FaceIndex????????????
//TempData???????????????????????��??��???��??Size?????
//?????��??�?????????????????????TempData???��?128K???
//???????????��??��?????��?????????????????0??????????????
 int UDK_API Z_GetUserFace(UDK_HANDLE Handle, char* PIN, int FaceIndex, 
											 char *TmpData, int *Size)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERFACE_RRQ;

	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//*(WORD*)TmpData=GetPIN1(h, PIN);
	memcpy(TmpData,PIN,24); 
	TmpData[24]=0;
	TmpData[25]=(char)FaceIndex;
	*Size=ZEMBPRO_READDATA1(h->emh,&cmd,TmpData,*Size,28,h->BlockSize,h->WaitTimeFor1KData);
	//*Size=ZEMBPRO_SENDCMD(h->emh, &cmd, TmpData, *Size, 3, h->WaitTimeFor1KData); 

	if(cmd==CMD_ACK_ERROR)
	{
		return Z_ERROR_NO_DATA;
	}
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//?????????��??�^
//???��??�I?????????0???????????1???????????
 int UDK_API Z_DelUserFace(UDK_HANDLE Handle, char* PIN, int FaceIndex)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_DELETE_USERFACE;
	char buf[28];
	int i;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	memcpy(buf,PIN,24); 
	buf[24]=0;
	buf[25]=(char)FaceIndex;	
	i=ZEMBPRO_SENDCMD(h->emh, &cmd, buf, 0, 28, 4000+h->WaitTimeForACommand);
	if(cmd==CMD_ACK_ERROR && i==2) return Z_ERROR_NO_DATA;
	if(cmd!=CMD_ACK_OK) return Z_ERROR_IO;
	return Z_ERROR_OK;
}

//upload user template 2006-8-30
//????????????��???
//?��??????��???????????????????1??????????????????0???????????

 int UDK_API Z_SetUserFace(UDK_HANDLE Handle, char *PIN, int FaceIndex, char *TmpData, int Size)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd=CMD_USERFACE_WRQ;
	char buf[28];
	char dataBuf[FACE_BUF_LEN]={0};
	int i,dataBufLen=0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	//memset(buf,0,28);

	//if((Size=TestTemplate41(TmpData, buf+28))>0) return Z_ERROR_UNSUPPORT;
	//dataBufLen = *(UDK_U16*)(TmpData) +2;
	dataBufLen = Size; //2576 * 15;
	if(dataBufLen>FACE_BUF_LEN) return Z_ERROR_SIZE;
	memcpy(dataBuf,TmpData,dataBufLen);

	memcpy(buf,PIN,24); 
	buf[24]=0;
	buf[25]=(char)FaceIndex;   
	*(UDK_U16*)(buf+26)=dataBufLen;		//buf[26]buf[27]

	i=ZEMBPRO_SENDCMDDATA(h->emh, &cmd, dataBuf, dataBufLen, buf , 28, h->WaitTimeFor1KData);

	if(cmd!=CMD_ACK_OK)
	{
		if(i==2) 
			return Z_ERROR_NO_DATA;
		else if(i==1)
			return Z_ERROR_NO_SPACE;
		else if(i==4)
			return Z_ERROR_DATA_EXISTED;
		else
			return Z_ERROR_IO;
	}
	return Z_ERROR_OK;
}

/*
?????? ZKFinger10.0 ??????????
????
Templates[]:??????????????
FingerCount:?????????????
TemplateDest:????????
Template2 must one finger only,but it is allow that template1 have multi finger
*/
//BIOKEY_API int BIOKEY_MERGE_TEMPLATE(UDK_U8 *Templates[],int FingerCount,UDK_U8 *TemplateDest)
 int UDK_API Z_MergeTemplate(UDK_U8 *Templates[],int FingerCount,UDK_U8 *TemplateDest)
{
	return BIOKEY_MERGE_TEMPLATE((unsigned char**)Templates,FingerCount,(unsigned char*)TemplateDest);
}

/*
?????? ZKFinger10.0 ??????????
????
Template:??????
Templates[]:?????????????
FingerCount?????????
FingerSize?????????��,??????????�??
Template2 must one finger only,but it is allow that template1 have multi finger
*/
//BIOKEY_API int BIOKEY_SPLIT_TEMPLATE(UDK_U8 *Template,UDK_U8 *Templates[], int *FingerCount,int *FingerSizes)
 int UDK_API Z_SplitTemplate(UDK_U8 *Template,UDK_U8 *Templates[], int *FingerCount,int *FingerSizes)
{
	return BIOKEY_SPLIT_TEMPLATE((unsigned char*)Template,(UDK_U8**)Templates,FingerCount,FingerSizes);
}

/*
???PIN???????????????????
????:
PIN:????
*/
 int UDK_API Z_ReadUserTempData(UDK_HANDLE Handle, char *PIN)
{
	PEmHandle h = (PEmHandle )Handle;
	int AtempUserID, Size;
	unsigned short Cmd = CMD_READTMP;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		//??????????????
		h->BufferLen=20*1024;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}

	//???????(h->BufferLen=20K)????????????????????????????
	if(h->BufferLen < 1*1024*1024)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL;
	}
	if(h->TmpSize==0 || h->TmpBuffer==NULL)
	{
		if (h->IsTFTMachine)
		{
			AtempUserID=SSR_GetPIN1(h,PIN);
		}
		else 
		{
			AtempUserID=GetPIN1(h,atoi(PIN));
		}


		if(AtempUserID < 0) 
		{
			return Z_ERROR_NO_DATA;
		}

		//h->Buffer[0] = 2;//??????
		((UDK_U16*)h->Buffer)[0] = AtempUserID; 
		Size = ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,
			h->BufferLen, (strcmp(h->version,VER504)<0)?0:2, h->BlockSize, h->WaitTimeFor1KData);
		if(Cmd==CMD_ACK_OK)
		{
			h->OLogSize=0;
			h->OLogBuffer=NULL;
			h->cOLogBuffer=NULL;
			h->cALogBuffer=NULL;
			h->ALogBuffer=NULL;
			h->ALogSize=0;
			h->UDataSize=0;
			h->UDataBuffer=NULL;
			h->cUDataBuffer=NULL; 
			h->TmpSize=*(int*)(h->Buffer);
			h->TmpBuffer=h->Buffer+4;
			h->cTmpBuffer=h->TmpBuffer;

			if(0 == h->TmpSize)         //????????????????????????,???????????????????
			{
				h->TmpSize = 1;
				((PTemplate)h->TmpBuffer)->FingerID = 0;
				((PTemplate)h->TmpBuffer)->PIN = 0;
				((PTemplate)h->TmpBuffer)->Size = 8;
				((PTemplate)h->TmpBuffer)->Template = 0;
				((PTemplate)h->TmpBuffer)->Valid = 0;
			}
			return Z_ERROR_OK;
		}
		else if(Cmd==CMD_ACK_ERROR && Size==0)
		{
			return Z_ERROR_NO_DATA;
		}	
		else
		{
			return Z_ERROR_IO;
		}
	}
    return Z_ERROR_NO_DATA;
}

/*
1???????????????
2???????????????buffer

???????1
*/
 int UDK_API Z_UpdateFile(UDK_HANDLE Handle, char *FileName)
{
	char *fdata = NULL;
	PEmHandle h = (PEmHandle )Handle; 
	unsigned short cmdHeader = CMD_CHECKUDISKUPDATEPACKPAGE;  //????????????
	unsigned short cmd = CMD_UPDATE_FIRMWARE;  //??????????
	int len, CmdBuf = 0;
	int ret = 0;
	char version[100] = {0};
	char header[200] = {0};                    //????????????
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	fdata = LoadFile(FileName, header, &len);   //???????????
	ret = ZEMBPRO_SENDCMD(h->emh, &cmdHeader, header, 0, strlen(header), 4*h->WaitTimeForACommand);
	if (cmdHeader != CMD_ACK_OK)
	{
		udk_free(fdata);
		if (ret == 1)
			return Z_ERROR_UNSUPPORT;
		else if (ret == 2)
			return Z_ERROR_NO_SPACE;
		else 
			return Z_ERROR_IO;
	}
	if(fdata)
	{
		CmdBuf = UPDATE_FILE;                     //��????
		ZEMBPRO_SENDCMDDATA(h->emh, &cmd, fdata, len, (char*)&CmdBuf, sizeof(CmdBuf), 4*h->WaitTimeForACommand);
		udk_free(fdata);
		if(cmd != CMD_ACK_OK) 
			return Z_ERROR_IO;
		return Z_ERROR_OK;
	}
	return Z_ERROR_PARAM;
}

/*????????????
????
NewLog??0???????��?? 1???????????????
*/
 int UDK_API Z_ReadLastestLog(UDK_HANDLE Handle, int NewLog, int dwYear, int dwMonth, int dwDay, int dwHour, int dwMinute, int dwSecond, int LastCount)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size, ResSize, SendLen = 0;
	TTime t = {0};
	unsigned short Cmd=CMD_ATTLOG_RRQ;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{  
		h->BufferLen=40*1024*1024;  //iclock880 ???????????900000??????????33.3M
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}

	//NewLog?True???????��???????????????
	if (NewLog)
	{
		t.tm_year = dwYear-1900;
		t.tm_mon = dwMonth-1;
		t.tm_mday = dwDay;
		t.tm_hour = dwHour;
		t.tm_min = dwMinute;
		t.tm_sec = dwSecond;
		*((UDK_U32*)h->Buffer) = OldEncodeTime(&t);
		SendLen = 8;
		if (LastCount >0)
		{
			*((UDK_U32*)h->Buffer+1) = LastCount;
		}
		else
		{
			*((UDK_U32*)h->Buffer+1) = 0;
		}
	}
	Size=ZEMBPRO_READDATA(h->emh,&Cmd, h->Buffer, h->BufferLen, SendLen, h->BlockSize, h->WaitTimeFor1KData);

	if(Cmd==CMD_ACK_OK && Size > 0)
	{
		h->TmpSize=0; 
		h->TmpBuffer=NULL; 
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cOLogBuffer=NULL;
		h->OLogBuffer=NULL;
		h->OLogSize=0;
		if (NewLog)
		{
			h->ALogSize=Size;
			h->ALogBuffer=h->Buffer;
		}
		else
		{
			h->ALogSize=*(int*)(h->Buffer);
			h->ALogBuffer=h->Buffer+4;
		}
		h->cALogBuffer=h->ALogBuffer;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

//???��?��???????????????????? add 2011-06-08
 int UDK_API Z_ReadOpLogEx(UDK_HANDLE Handle, int dwYear_S, int dwMonth_S, int dwDay_S, int dwHour_S, int dwMinute_S, int dwSecond_S,
											 int dwYear_E, int dwMonth_E, int dwDay_E, int dwHour_E, int dwMinute_E, int dwSecond_E, int dwLogIndex)
{
	PEmHandle h = (PEmHandle )Handle;
	int Size;
	unsigned short Cmd = CMD_OPLOG_RRQ_EX;
	struct tm time_s;
	struct tm time_e;
	UDK_U32 t_s;
	UDK_U32 t_e;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	if(strcmp(h->version,VER504)<0) return Z_ERROR_NO_DATA;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		h->BufferLen=2*1024*1024*3;
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}	

	time_s.tm_hour=dwHour_S;
	time_s.tm_mday=dwDay_S;
	time_s.tm_min=dwMinute_S;
	time_s.tm_mon=dwMonth_S;  //tm_mon of struct tm is from 0 to 11
	time_s.tm_sec=dwSecond_S;
	time_s.tm_year=dwYear_S;
	t_s=EncodeTime(&time_s);//??????

	time_e.tm_hour=dwHour_E;
	time_e.tm_mday=dwDay_E;
	time_e.tm_min=dwMinute_E;
	time_e.tm_mon=dwMonth_E;
	time_e.tm_sec=dwSecond_E;
	time_e.tm_year=dwYear_E;
	t_e=EncodeTime(&time_e);//??????

	memcpy(h->Buffer, &dwLogIndex, 4);   //dwLogIndex????0??????????��??????dwLogIndex?????????????
	memcpy(h->Buffer+4, &t_s, 4);
	memcpy(h->Buffer+8, &t_e, 4);

	Size=ZEMBPRO_READDATA(h->emh,&Cmd,h->Buffer,h->BufferLen,12, h->BlockSize, h->WaitTimeFor1KData);
	if(Cmd==CMD_ACK_OK)
	{
		h->TmpSize=0;
		h->TmpBuffer=NULL;
		h->cTmpBuffer=NULL; 
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->cALogBuffer=NULL;
		h->ALogBuffer=NULL;
		h->ALogSize=0;
		h->OLogSizeEx=*(int*)(h->Buffer);
		h->OLogBufferEx=h->Buffer+4;
		h->cOLogBufferEx=h->OLogBufferEx;
		return Z_ERROR_OK;
	}
	else if(Cmd==CMD_ACK_ERROR && Size==0)
	{
		return Z_ERROR_NO_DATA;
	}
	else
		return Z_ERROR_IO;
}

 int UDK_API Z_GetOpLogEx(UDK_HANDLE Handle, int *PIN, int *OP, int *Params,
											int *Year, int *Month, int *Day, int *Hour, int *Minute, int *Second,char *PIN2)
{
	PEmHandle h = (PEmHandle )Handle;
	TTime t = {0};
	int i;

	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(strcmp(h->version, VER504) < 0)
	{
		return Z_ERROR_NO_DATA;
	}
	if(h->OLogSizeEx == 0 || h->Buffer == NULL)
	{
		//??��??????????????????
		return Z_ERROR_IO;
	}
	if(h->OLogSizeEx==0 || h->OLogBufferEx==NULL)
	{
		return Z_ERROR_NO_DATA;
	}

	if(h->cOLogBufferEx < (h->OLogBufferEx + h->OLogSizeEx))
	{
		POPLogEx log = (POPLogEx)h->cOLogBufferEx;
		i = sizeof(TOPLogEx);
		h->cOLogBufferEx += i;//???????????
		if((log->Admin == 0xFFFF) || (h->cOLogBuffer > h->Buffer + h->BufferLen))
		{
			return Z_ERROR_NO_DATA;
		}
		strcpy(PIN2,log->PIN2);
		*PIN = log->Admin;
		*OP = log->OP;
		Params[0] = log->Users[0];
		Params[1] = log->Users[1];
		Params[2] = log->Users[2];
		Params[3] = log->Users[3];
		DecodeTime(log->time_second, &t);
		*Year = t.tm_year;
		*Month = t.tm_mon;
		*Day = t.tm_mday;
		*Hour = t.tm_hour;
		*Minute = t.tm_min;
		*Second = t.tm_sec;
	}
	else
		return Z_ERROR_NO_DATA;
	return Z_ERROR_OK;
}

 int UDK_API Z_GetPhotoByName(UDK_HANDLE Handle, char *photoname, char *PhotoData, int *Size)//?????????????????
{
	PEmHandle h = (PEmHandle )Handle;
	char *buffer = NULL;
	unsigned short cmd = CMD_GET_PHOTO_BYNAME;
	buffer = (char *)udk_malloc(*Size);
	memset(buffer, 0, *Size);
	strcpy(buffer, photoname);
	*Size = ZEMBPRO_READDATA(h->emh ,&cmd, buffer, 180*1024, strlen(photoname)+1, h->BlockSize, 2000 + h->WaitTimeFor1KData);
	if(cmd == CMD_ACK_OK)
	{
		memcpy(PhotoData, buffer, *Size);
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_OK;
	}
	else
	{
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_IO;
	}
}
//??????????????????????
 int UDK_API Z_GetPhotoNamesByTime(UDK_HANDLE Handle, int syear, int smonth, int sday, int shour, int sminute, int ssecond, int eyear,
													 int emonth, int eday, int ehour, int eminute, int esecond, int iFlag, char* PhotoNames)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_GET_PHOTONAMES_BY_TIME;
	struct tm time_s;
	struct tm time_e;
	UDK_U32 t_s;
	UDK_U32 t_e;
	if(NULL==h)	return Z_ERROR_NOT_INIT;

	time_s.tm_hour = shour;
	time_s.tm_mday = sday;
	time_s.tm_min = sminute;
	time_s.tm_mon = smonth;  //tm_mon of struct tm is from 0 to 11
	time_s.tm_sec = ssecond;
	time_s.tm_year = syear;
	t_s = EncodeTime(&time_s);//??????

	time_e.tm_hour = ehour;
	time_e.tm_mday = eday;
	time_e.tm_min = eminute;
	time_e.tm_mon = emonth;  //tm_mon of struct tm is from 0 to 11
	time_e.tm_sec = esecond;
	time_e.tm_year = eyear;
	t_e = EncodeTime(&time_e);//???????

	memcpy(PhotoNames, &iFlag, 4);
	memcpy(PhotoNames+4, &t_s, 4);
	memcpy(PhotoNames+8, &t_e, 4);
	ZEMBPRO_READDATA(h->emh, &cmd, PhotoNames, 180*1024, 12, h->BlockSize, 2000+h->WaitTimeFor1KData);
	if(cmd == CMD_ACK_OK)
		return Z_ERROR_OK;
	return Z_ERROR_IO;
}
//???????????????
 int UDK_API Z_ClearPhotoByTime(UDK_HANDLE Handle, int syear, int smonth, int sday, int shour, int sminute, int ssecond, int eyear,
												  int emonth, int eday, int ehour, int eminute, int esecond, int iFlag)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_CLEAR_PHOTO_BY_TIME;
	char *buffer = NULL;

	struct tm time_s;
	struct tm time_e;
	UDK_U32 t_s;
	UDK_U32 t_e;
	if(NULL == h)	
		return Z_ERROR_NOT_INIT;
	buffer = (char *)udk_malloc(12);
	memset(buffer, 0, 12);

	time_s.tm_hour = shour;
	time_s.tm_mday = sday;
	time_s.tm_min = sminute;
	time_s.tm_mon = smonth;  //tm_mon of struct tm is from 0 to 11
	time_s.tm_sec = ssecond;
	time_s.tm_year = syear;
	t_s = EncodeTime(&time_s);//??????

	time_e.tm_hour = ehour;
	time_e.tm_mday = eday;
	time_e.tm_min = eminute;
	time_e.tm_mon = emonth;  //tm_mon of struct tm is from 0 to 11
	time_e.tm_sec = esecond;
	time_e.tm_year = eyear;
	t_e = EncodeTime(&time_e);//???????

	memcpy(buffer, &iFlag, 4);
	memcpy(buffer+4, &t_s, 4);
	memcpy(buffer+8, &t_e, 4);
	ZEMBPRO_SENDCMD(h->emh, &cmd, buffer, 12, 12, 3000+h->WaitTimeForACommand);
	udk_free(buffer);
	buffer = NULL;
	if(cmd == CMD_ACK_OK)
		return Z_ERROR_OK;
	return Z_ERROR_IO;
}

 int UDK_API Z_GetPhotoCount(UDK_HANDLE Handle, int iFlag, char *photocount) // ??????????????
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_GET_PHOTO_COUNT;
	memcpy(photocount, &iFlag, 4);
	if(NULL == h)	
		return Z_ERROR_NOT_INIT;
	ZEMBPRO_SENDCMD(h->emh, &cmd, photocount, 10, 4, 3000+h->WaitTimeForACommand);
	if(cmd == CMD_ACK_OK)
	{
		return Z_ERROR_OK;
	}
	return Z_ERROR_IO;
}

 int UDK_API Z_ReadLargeTmp(UDK_HANDLE Handle)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_READ_LARGE_TMP;
	int size = 0;
	int reclen = 0;

	if(NULL == h)	return Z_ERROR_NOT_INIT;
	if(h->BufferLen==0 || h->Buffer==NULL)
	{
		//??????????????
		h->BufferLen=70*1024*1024;//5???10?????
		h->Buffer=(char*)udk_malloc(h->BufferLen);
	}

	size = READDATA_PICE_BY_PICE(h->emh,&cmd,h->Buffer,0,h->Buffer,h->BufferLen,TRUE,50000000,&reclen);

	if(cmd==CMD_ACK_OK)
	{
		h->OLogSize=0;
		h->OLogBuffer=NULL;
		h->cOLogBuffer=NULL;
		h->cALogBuffer=NULL;
		h->ALogBuffer=NULL;
		h->ALogSize=0;
		h->UDataSize=0;
		h->UDataBuffer=NULL;
		h->cUDataBuffer=NULL; 
		h->TmpSize=size;
		h->TmpBuffer=h->Buffer;
		h->cTmpBuffer=h->TmpBuffer;
		return Z_ERROR_OK;
	}
	return Z_ERROR_IO;
}

 int UDK_API InitQuickUserTempEx(UDK_HANDLE Handle)
{                              
	PEmHandle h = (PEmHandle )Handle;
	PTemplate tmp;
	UDK_U16 PINTemp;
	char *dataBuf=NULL;
	int temlen;
	int ret;
	int sizeOffset=0;


	sizeOffset = 0;
	if(NULL==h)	return Z_ERROR_NOT_INIT;
	tmp=(PTemplate)h->TmpBuffer;
	memset((char*)h->fingerquicksearch, 0,sizeof(h->fingerquicksearch));
	while((unsigned long)tmp<(unsigned long)(h->TmpBuffer+h->TmpSize))
	{	
		if(tmp->PIN > 50000)
		{
			printf("%d\n",tmp->PIN);
			break;
		}
		switch(tmp->FingerID)
		{
		case 0:
			h->fingerquicksearch[tmp->PIN].index0 = sizeOffset+6;
			break;
		case 1:
			h->fingerquicksearch[tmp->PIN].index1 = sizeOffset+6;
			break;
		case 2:
			h->fingerquicksearch[tmp->PIN].index2 = sizeOffset+6;
			break;
		case 3:
			h->fingerquicksearch[tmp->PIN].index3 = sizeOffset+6;
			break;
		case 4:
			h->fingerquicksearch[tmp->PIN].index4 = sizeOffset+6;
			break;
		case 5:
			h->fingerquicksearch[tmp->PIN].index5 = sizeOffset+6;
			break;
		case 6:
			h->fingerquicksearch[tmp->PIN].index6 = sizeOffset+6;
			break;
		case 7:
			h->fingerquicksearch[tmp->PIN].index7 = sizeOffset+6;
			break;
		case 8:
			h->fingerquicksearch[tmp->PIN].index8 = sizeOffset+6;
			break;
		case 9:
			h->fingerquicksearch[tmp->PIN].index9 = sizeOffset+6;
			break;
		default:
			break;
		}
		sizeOffset += tmp->Size;
		tmp=(PTemplate)(((char*)tmp)+tmp->Size);

	}
	return Z_ERROR_OK;
}
 int UDK_API Z_SendFile_mtd(UDK_HANDLE Handle, char *FileName)
{
	PEmHandle h = (PEmHandle )Handle; 
	unsigned short cmd = CMD_UPDATE_FIRMWARE;
	char cmdBuf[40] = {0};
	FILE *fp = NULL;
	int SendLen = 0;
	char *buffer = NULL;
	ssize_t retsize;
	if(FileName == NULL)
	{
		return Z_ERROR_PARAM;
	}
	if(NULL == h)	
	{
		return Z_ERROR_NOT_INIT;
	}	

	//�ҵ��ļ���,�������������	
	//*((int*)cmdBuf) = UPDATE_FIRMWARE;	
	*((int*)cmdBuf) = UPDATE_CFIRMWARE;
	if(strrchr(FileName, '\\') == NULL)
	{
		strcpy(cmdBuf+4,FileName);
	}
	else
	{
		strcpy(cmdBuf+4, strrchr(FileName, '\\') + 1);
	}	

	buffer = (char *)udk_malloc(CUSTFILESIZE);
	if(buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(buffer, 0, CUSTFILESIZE);

	//����ݶ�����ʱ���������͡�
	fp = fopen(FileName, "rb");
	if(fp == NULL)
	{
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_IO;
	}
	fseek(fp, 0, SEEK_END);
	SendLen = ftell(fp);	
	fseek(fp, 0, SEEK_SET);
	retsize = fread(buffer, SendLen, 1, fp);

	Z_DisableDevice(Handle, 3);

	ZEMBPRO_SENDCMDDATA(h->emh, &cmd, buffer, SendLen, cmdBuf, strlen(FileName) + 4 + 1, 4*h->WaitTimeForACommand);
	Z_EnableDevice(Handle);

	fclose(fp);
	udk_free(buffer);
	buffer = NULL;

	if(cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	else
	{
		return Z_ERROR_OK;
	}
}

 UDK_HANDLE UDK_API Z_Connect_P4P(char* uid, void* ReadFun, void* Param, int CommKey)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	int i = 0;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version, VER504);	//"Ver 5.04 Sep 30 2004"
	h->emh=ZEMBPRO_INIT("p4pcomm.dll",uid,0,0, (ReadCallBack)ReadFun, Param, CommKey);
	//h->emh=ZEMBPRO_INIT("tcpcomm.dll",IPAddress,(unsigned short)DevicePort,0, (ReadCallBack)ReadFun, Param, CommKey, NULL);
	h->WaitTimeForACommand=4000;
	h->WaitTimeFor1KData=4000;
	h->BlockSize=16*1024;
	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
		return h;
	}
	else
	{
		if(!getDeviceBaseInfo(h))
		{
			Z_Close(h);
			h=NULL;
		}
	}
	return h;
}

 UDK_HANDLE UDK_API Z_Connect_USB_STD(int DeviceNumber, void* ReadFun, void *Param, int CommKey)
{
	PEmHandle h=(PEmHandle)udk_malloc(sizeof(TEmHandle));
	char *s = NULL;
	int i = 0;
	memset(h, 0, sizeof(TEmHandle));
	sprintf(h->version,VER504);
	//h->emh=ZEMBPRO_INIT("usbstd.dll", "", DeviceNumber, 0, (ReadCallBack)ReadFun, Param, CommKey, NULL);
	h->emh=ZEMBPRO_INIT("usbstd.dll", "", DeviceNumber, 0, NULL, Param, CommKey);
	h->BlockSize=1024;	//�˴�С���ܸ��
	h->WaitTimeForACommand=4000;
	h->WaitTimeFor1KData=4000;

	if(NULL==h->emh)
	{
		udk_free(h);
		h=NULL;
		return h;
	}
	else
	{
		if(Z_ERROR_OK==Z_GetFirmwareVersion(h, h->version))
		{
			UDK_LOGD("readfirmware version ok\n");
			h->libusb_flag = 1;
			ConvertMonth(h->version);
			s = ReadOption(h,"~OS");
			if(!s || !strlen(s) || !strcmp(s,"NONE"))
				h->DeviceType = 0;
			else
				h->DeviceType = 1;
			//����Ƿ�洢��չ��¼
			s = ReadOption(h,"~ExtendFmt");
			if(!s)
				h->ExtendFmt=0;
			else
				h->ExtendFmt=atoi(s);

			//henry 2007-21 modify for events
			//when ver<6.01,reg events auto.
			if(strcmp(h->version,VER601)<0)
			{
				Z_RegEvent(h, 0x7FFF);
			}
			h->RTLogNum=0;

			//dsl.2007.07.04
			s = ReadOption(h,"~Platform");			
			if (s)
			{
				h->IsTFTMachine = 0;
				h->NewSmsFormat = 0;
				if (strstr(s, "TFT"))
				{
					h->IsTFTMachine = 1;
					h->NewSmsFormat = 1;
				}				
			}
			else
			{
				h->NewSmsFormat = 0;
				h->IsTFTMachine = 0;
			}

			//dsl 2007.9.20						
			h->IsNewRTStru = 0;
			if ( (strcmp(h->version, VER61820070807) > 0) && (!h->IsTFTMachine))
			{
				h->IsNewRTStru = 1;
			}		

			s = ReadOption(h,"~ZKFPVersion");
			if(!s|| !strlen(s) || !strcmp(s,"NONE"))
				h->EmKeyOptions.ZKFPVersion = 9;
			else
				h->EmKeyOptions.ZKFPVersion = atoi(s);
		}
		else
		{
			Z_Close(h);
			h=NULL;
		}
	}
	return h;
}

 int UDK_API Z_SetDeviceData(UDK_HANDLE Handle, char *tableName, char *Datas, char *options)
{
	PEmHandle h = (PEmHandle )Handle;
	unsigned short cmd = CMD_SET_DATA;
	char rowDatas[5 * 1024];

	if (NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}

	snprintf(rowDatas, sizeof(rowDatas), "TableName=%s\r\n%s", tableName, Datas);

	ZEMBPRO_SENDCMD(h->emh, &cmd, (char*)rowDatas, strlen(rowDatas), sizeof(rowDatas), 2000 + h->WaitTimeForACommand);
	
	if (CMD_ACK_OK == cmd)
	{
		;
	}
	else
	{
		return Z_ERROR_IO;
	}

	return Z_ERROR_OK;
}

 int UDK_API Z_SetCommuTimeOut(UDK_HANDLE Handle, int timeOut)
{
	PEmHandle h = (PEmHandle )Handle;

	if (NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}

	if (timeOut >= 0)
	{
		h->WaitTimeFor1KData = timeOut * 1000;
		h->WaitTimeForACommand = timeOut * 1000;
	}

	return Z_ERROR_OK;
}
 int UDK_API Z_SendFileByType(UDK_HANDLE Handle, char *FileName,int iType)
{
	PEmHandle h = (PEmHandle )Handle; 
	unsigned short cmd = CMD_UPDATE_FIRMWARE;
	char cmdBuf[40] = {0};
	FILE *fp = NULL;
	int SendLen = 0;
	char *buffer = NULL;
	ssize_t retsize;

	if(FileName == NULL)
	{
		return Z_ERROR_PARAM;
	}
	if(NULL == h)	
	{
		return Z_ERROR_NOT_INIT;
	}	

	//????????,??????????????	
	*((int*)cmdBuf) = iType;//CMD_UPDATEFILE;	
	if(strrchr(FileName, '\\') == NULL)
	{
		strcpy(cmdBuf+4,FileName);
	}
	else
	{
		strcpy(cmdBuf+4, strrchr(FileName, '\\') + 1);
	}	



	//??????????????????????
	fp = fopen(FileName, "rb");
	if(fp == NULL)
	{
		udk_free(buffer);
		buffer = NULL;
		return Z_ERROR_IO;
	}
	fseek(fp, 0, SEEK_END);
	SendLen = ftell(fp);	
	fseek(fp, 0, SEEK_SET);

	if(SendLen<CUSTFILESIZE)
	{
		buffer = (char *)udk_malloc(CUSTFILESIZE);
	}
	else
	{
		buffer = (char *)udk_malloc(SendLen);
	}

	
	if(buffer == NULL)
	{
		return Z_ERROR_NO_SPACE;
	}
	memset(buffer, 0, SendLen);
	retsize = fread(buffer, SendLen, 1, fp);

	Z_DisableDevice(Handle, 3);

	ZEMBPRO_SENDCMDDATA(h->emh, &cmd, buffer, SendLen, cmdBuf, strlen(FileName) + 4 + 1, 4*h->WaitTimeForACommand);
	Z_EnableDevice(Handle);

	fclose(fp);
	udk_free(buffer);
	buffer = NULL;

	if(cmd != CMD_ACK_OK)
	{
		return Z_ERROR_IO;
	}
	else
	{
		return Z_ERROR_OK;
	}
}
 int UDK_API Z_SetParameters(UDK_HANDLE Handle, int nCode, int nValue)
{
	PEmHandle h = (PEmHandle )Handle; 
	if (NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if (nCode == PARAMETERCODE_COMPATOLDFIRMWARE)
	{
	  h->bNewFirmware = (nValue == 0);
	}
	return Z_ERROR_OK;
}


int UDK_API Z_SearchDevice(char *CommType,char *Address, char *Buffer,int *BufferSize)
{
    char sendbuf[128];
    int sendlen=0, buflen=0, ret=0;
    PST_COMM_MODULE intf = find_comm_module_by_proto(CommType);
    if(intf){
	char* commlib = strdup(intf->comm_lib);
	if(!strcmp(CommType,"UDP") || !strcmp(CommType,"Eth") || !strcmp(CommType,"Ethernet")){
		sendlen = sprintf(sendbuf, "X");		
		ret=ZEMBPRO_BROADCAST(commlib, Address ,sendbuf,sendlen,Buffer,BufferSize,3000);
	}
	udk_free(commlib);
    }else if(strcmp(CommType,"UDP")==0 || strcmp(CommType,"Eth")==0 || strcmp(CommType,"Ethernet")==0){
	sendlen = sprintf(sendbuf, "X");
	ret=ZEMBPRO_BROADCAST((char*)(UDK_RTLIBPREFIX COMMPRO_UDP_LIB UDK_RTLIBSUFFIX), Address,
				       sendbuf, sendlen,Buffer,BufferSize, 3000);		
    }

    return ret;
  
}

int UDK_API Z_MobileAtt(UDK_HANDLE Handle, int operate, char *premeters, char *Buffer,int *BufferSize)
{
	int ret = 0;
	PEmHandle h = (PEmHandle )Handle;
	char *tempBuffer = NULL;
	unsigned short Cmd = 0;
	unsigned short SendCmd = 0;
	int nInputLen = *BufferSize;
	*BufferSize = 0;
	if (NULL == h)
	{
		UDK_LOGE("Z_MobileAtt not init");
		return Z_ERROR_NOT_INIT;
	}
	switch(operate)
	{
	case OP_QUERY_TOKEN:
	case OP_APP_SET_TOKEN:
	case OP_APP_WIFI_CHECKIN:
		if(OP_QUERY_TOKEN == operate) Cmd = CMD_APP_QUERY_TOKEN;
		else if (OP_APP_SET_TOKEN == operate) Cmd = CMD_APP_SET_TOKEN;
		else Cmd = CMD_APP_WIFI_CHECKIN;
		SendCmd = Cmd;
		tempBuffer = (char*)udk_malloc(1024);
		if(NULL == tempBuffer)
		{
			UDK_LOGE("Z_MobileAtt Malloc faile\n");
			ret = Z_ERROR_MEMORY;
			break;
		}
		memset(tempBuffer, 0, 1024);
		strcpy(tempBuffer, premeters);
		ret = ZEMBPRO_SENDCMD(h->emh, &Cmd, tempBuffer,1024, strlen(premeters)+1, 4*h->WaitTimeForACommand);
		if(Cmd == CMD_ACK_OK)
		{
			if(nInputLen < strlen(tempBuffer))
			{
				ret = Z_ERROR_MEMORY;
				break;
			}
			*BufferSize = strlen(tempBuffer);
			strcpy(Buffer, tempBuffer);
			ret = Z_ERROR_OK;
			break;
		}
		else if(Cmd > 2000 && Cmd < 3000)
		{
			ret = (-Cmd);
			break;
		}
		else
		{
			ret = (ret<0?ret:Z_ERROR_IO);
			break;
		}
		break;
	case OP_APP_PULL_PERSONAL_REPORTS:
	case OP_APP_PULL_COMPANY_REPORTS:
		if(OP_APP_PULL_PERSONAL_REPORTS == operate) Cmd = CMD_APP_PULL_PERSONAL_REPORTS;
		else Cmd = CMD_APP_PULL_COMPANY_REPORTS;
		SendCmd = Cmd;
		tempBuffer = (char*)udk_malloc(MAX_REPORT_SIZE);
		if(NULL == tempBuffer)
		{
			UDK_LOGE("Z_MobileAtt Malloc faile\n");
			ret = Z_ERROR_MEMORY;
			break;
		}
		memset(tempBuffer, 0, MAX_REPORT_SIZE);
		strcpy(tempBuffer, premeters);
		ret = ZEMBPRO_READDATA(h->emh, &Cmd, tempBuffer, MAX_REPORT_SIZE, strlen(premeters)+1, h->BlockSize, 2*h->WaitTimeFor1KData);
		if(ret > 0)
		{
			int sizeLength = sizeof(int);
			char* pDataBuffer = tempBuffer + sizeLength;	//not care total length
			int nSummarySize = 0;
			int nDetailSize = 0;
			const char *split = "\n\t\r";
			int splitLen = strlen(split);
			if(ret < sizeLength)	//invalid length
			{
				ret = Z_ERROR_SIZE;
				break;
			}
			memcpy(&nSummarySize, pDataBuffer, sizeof(int));
			if (ret < nSummarySize + sizeLength)	//invalid length
			{
				ret = Z_ERROR_SIZE;
				break;
			}
			else if (ret >= nSummarySize + 2*sizeLength)	//have detail length
			{
				memcpy(&nDetailSize, pDataBuffer+sizeLength+nSummarySize, sizeof(int));
				if (ret < nSummarySize + 2*sizeLength + nDetailSize)	//invalid length
				{
					ret = Z_ERROR_SIZE;
					break;
				}
			}
			if(nInputLen < nSummarySize + nDetailSize + splitLen)	//input buffer not enough
			{
				UDK_LOGE("Z_MobileAtt ZEMBPRO_READDATA succ, but length no enough, buflen=%d, totalsize=%d\n", 
					nInputLen, nSummarySize + nDetailSize + splitLen);
				ret = Z_ERROR_MEMORY;
				break;
			}
			else
			{
				int nPos = 0;
				if(nSummarySize>0)
				{
					memcpy(Buffer+nPos, pDataBuffer+sizeLength, nSummarySize);
					nPos += nSummarySize;
				}
				strcpy(Buffer+nPos, split);
				nPos += splitLen;
				if(nDetailSize>0)
				{
					memcpy(Buffer+nPos, pDataBuffer+sizeLength+nSummarySize+sizeLength, nDetailSize);
					nPos += nDetailSize;
				}
				*BufferSize = nPos;
				ret = Z_ERROR_OK;
				break;
			}
		}
		else if(Cmd > 2000 && Cmd < 3000)
		{
			ret = (-Cmd);
			break;
		}
		else
		{
			ret = (ret<0?ret:Z_ERROR_IO);
			break;
		}
		break;
	case OP_APP_PULL_ATT_RECOREDS:
		Cmd = CMD_APP_PULL_ATT_RECOREDS;
		SendCmd = Cmd;
		tempBuffer = (char*)udk_malloc(MAX_REPORT_SIZE);
		if(NULL == tempBuffer)
		{
			ret = Z_ERROR_MEMORY;
			break;
		}
		memset(tempBuffer, 0, MAX_REPORT_SIZE);
		strcpy(tempBuffer, premeters);
		ret = ZEMBPRO_READDATA(h->emh, &Cmd, tempBuffer, MAX_REPORT_SIZE, strlen(premeters)+1, h->BlockSize, 2*h->WaitTimeFor1KData);
		if(ret > 0)
		{
			int sizeLength = sizeof(int);
			int recvdatalen = 0;
			char* pDataBuffer = tempBuffer + sizeLength;
			if(ret < sizeLength)	//invalid length
			{
				ret = Z_ERROR_SIZE;
				break;
			}
			memcpy(&recvdatalen, tempBuffer, sizeLength);
			if(ret < sizeLength + recvdatalen)
			{
				ret = Z_ERROR_SIZE;
				break;
			}
			if(nInputLen < recvdatalen)
			{
				ret = Z_ERROR_MEMORY;
				break;
			}
			memcpy(Buffer, pDataBuffer, recvdatalen);
			*BufferSize = recvdatalen;
			ret = Z_ERROR_OK;
			break;
		}
		else if(Cmd > 2000 && Cmd < 3000)
		{
			ret = (-Cmd);
			break;
		}
		else
		{
			ret = (ret<0?ret:Z_ERROR_IO);
			break;
		}
		break;
	default:
		{
			ret = Z_ERROR_UNSUPPORT;
			break;
		}
	}
	if (NULL != tempBuffer)
		udk_free(tempBuffer);
	return ret;
}


int UDK_API Z_SetDownloadProcessCallBack(UDK_HANDLE Handle, void *pCallBackFun)
{
	PEmHandle h = (PEmHandle )Handle;
	if(NULL == h)
	{
		return Z_ERROR_NOT_INIT;
	}
	if(NULL == pCallBackFun)
	{
		return Z_ERROR_PARAM;
	}
	ZEMBPRO_SetDownloadProcessCallBack(h->emh, pCallBackFun);
	return Z_ERROR_OK;
}



